応用[SPRING]映画/レビュー項目-(1)
ファイルをアップロードしてムービーを登録し、ユーザーがムービーコメントを記録する例を作成します.映画の登録と修正ファイルアップロード機能を使用して映画ポスターなどを配置する. メンバーは、既存のメンバーが存在すると仮定し、データベースに存在するメンバーを使用します. 会員は、特定の映画閲覧ページで採点と自分の感想をコメントすることができます. ブラウズ画面では、会員は記録されたコメント内容を変更/削除することができます. コントローラパッケージは、ムービーコントローラクラスを作成します. 映画登録用の「/movie/register」を追加します. テンプレートにムービーフォルダを追加して登録します.htmlを作成します. MovieDTO/MovieImageDTOクラスおよびMovieService ムービーはエンティティークラスの処理を完了したので、DTOとサービス層のみが処理されます. MovieDTOはMovieクラスに基づいて作成されます. MovieDTOクラスの内部にアップロードファイルの情報が含まれている必要があるため、MovieImageDTOクラスを追加します. 映画の画像については、MovieImageDTOは以前のUploadResultDTOと同じである. プロジェクトにサービスパッケージを追加し、MovieServiceインタフェースとMovieServiceImplクラスを追加します. のdtoEntity()が追加され、MovieオブジェクトとMovieImageオブジェクトのリストがMapタイプで処理されます.
HashMapの重要な特性
-HAshMapには、「コピー可能」および「シリアル化可能」インタフェースも用意されています.
-HAshMapでは値の繰り返しは許可されますが、キーの繰り返しは許可されません.
-HAshMapでは複数のNull値も許可されていますが、Nullキーは1つしかありません.
-HAshMapは同期せず、要素の順序も保証されません.
MovieServiceImplは、MovieRepositoryとMovieImageRepositoryを受信し、dtoEntityで返されるオブジェクトを使用してsave()を処理するように構成されています.
MovieController MovieDTOを介してPOST方式で伝達するパラメータを収集するMovieServiceオブジェクトを呼び出すレジスタ() .添付ファイルの領域 画面では、まず添付ファイルのアップロードを処理します. このプロセスでは、画面上のアップロードファイルを同時に処理する必要があります. register.htmlにファイル部分をアップロードするクラスは「custom-file-input」で、イベントの処理に使用できます. 画面では、添付ファイルのアップロードによって変更イベントが処理され、ボタンなしでファイルの選択時に自動的に実行されます.
通常の処理でアップロードすると、画面に島図領域を追加して島図を表示する必要があります. register.htmldml Ajaxを呼び出すと、showResult()という個別の関数として処理されます. register.htmlの一部を変更し、showResult()を呼び出します.
各画像は、ImageDTOに必要な属性を構成するタグで構成される.
映画登録処理
@Controller
@Log4j2
@RequestMapping("/movie")
public class MovieController {
@GetMapping("/register")
public void register(){
}
}
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<th:block th:replace="~{/layout/basic :: setContent(~{this::content} )}">
<th:block th:fragment="content">
<h1 class="mt-4">Movie Register Page></h1>
<form th:action="@{/movie/register}" th:method="post">
<div class="form-group">
<label>Title</label>
<input type="text" class="form-control" name="title" placeholder="Entier Title">
</div>
<div class="form-group FileForm">
<label>Image Files</label>
<div class="custom-file">
<input type="file" class="custom-file-input files" id="fileInput" multiple>
<label class="custom-file-label" data-breose="Browse"></label>
</div>
</div>
<div class="box">
</div>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
<script>
$(document).ready(function(e){
}); //document ready
</script>
</th:block>
</th:block>
</html>
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class MovieDTO {
private Long mno;
private String title;
@Builder.Default
private List<MovieImageDTO> imageDTOList = new ArrayList<>();
//화면에 영화 이미지들도 같이 수집해서 전달해야 하므로 내부적으로 리스트를 이용하여 수집합니다.
}
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class MovieImageDTO {
private String uuid;
private String imgName;
private String path;
public String getImageURL(){
try{
return URLEncoder.encode(path + File.separator + uuid + "_" +imgName,"UTF-8");
}catch (UnsupportedEncodingException e){
e.printStackTrace();
}
return "";
}
public String getThumbnailURL(){
try{
return URLEncoder.encode(path+"/s"+uuid+"_"+imgName,"UTF-8");
}catch (UnsupportedEncodingException e){
e.printStackTrace();
}
return "";
}
}
public interface MovieService {
Long register(MovieDTO movieDTO);
default Map<String,Object> dtoToEntity(MovieDTO movieDTO){ //Map타입으로 반환
Map<String,Object> entityMap = new HashMap<>();
//key값을 String, Value값을 Object형으로
Movie movie = Movie.builder()
.mno(movieDTO.getMno())
.title(movieDTO.getTitle())
.build();
entityMap.put("movie",movie);
//Map에 키,값 저장
List<MovieImageDTO> imageDTOList = movieDTO.getImageDTOList();
//MovieImageDTO 처리
if(imageDTOList != null && imageDTOList.size() > 0){
//리스트는 stream()으로 해결하는것이 편하다.
List<MovieImage> movieImageList = imageDTOList.stream().map(movieImageDTO -> {
MovieImage movieImage = MovieImage.builder()
.path(movieImageDTO.getPath())
.imgName(movieImageDTO.getImgName())
.uuid(movieImageDTO.getUuid())
.movie(movie)
.build();
return movieImage;
}).collect(Collectors.toList());//List로 변환
entityMap.put("imageList",movieImageList);
//Map에 키,값 저장
}
return entityMap;
}
}
HashMapの重要な特性
-HAshMapには、「コピー可能」および「シリアル化可能」インタフェースも用意されています.
-HAshMapでは値の繰り返しは許可されますが、キーの繰り返しは許可されません.
-HAshMapでは複数のNull値も許可されていますが、Nullキーは1つしかありません.
-HAshMapは同期せず、要素の順序も保証されません.
MovieServiceImplは、MovieRepositoryとMovieImageRepositoryを受信し、dtoEntityで返されるオブジェクトを使用してsave()を処理するように構成されています.
@Serviceva
@Log4j2
@RequiredArgsConstructor
public class MovieServiceImpl implements MovieService{
private final MovieRepository movieRepository;
private final MovieImageRepository movieImageRepository;
@Override
@Transactional
public Long register(MovieDTO movieDTO) {
Map<String,Object> entityMap = dtoToEntity(movieDTO);
Movie movie = (Movie) entityMap.get("movie");
List<MovieImage> movieImageList =(List<MovieImage>) entityMap.get("imgList");
//Map에서 꺼내온 값들을 Movie,List<MovieImage>로 형변환
movieRepository.save(movie);
movieImageList.forEach(movieImage -> {
movieImageRepository.save(movieImage);
});
return movie.getMno();
}
}
@Controller
@Log4j2
@RequestMapping("/movie")
@RequiredArgsConstructor
public class MovieController {
private final MovieService movieService;
@GetMapping("/register")
public void register(){
}
@PostMapping("/register")
public String register(MovieDTO movieDTO, RedirectAttributes redirectAttributes){
log.info("movieDTO: "+movieDTO);
Long mno = movieService.register(movieDTO);
redirectAttributes.addFlashAttribute("msg",mno);
return "redirect:/movie/list";
}
}
処理表示<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<th:block th:replace="~{/layout/basic :: setContent(~{this::content} )}">
<th:block th:fragment="content">
<h1 class="mt-4">Movie Register Page</h1>
<form th:action="@{/movie/register}" th:method="post">
<div class="form-group">
<label>Title</label>
<input type="text" class="form-control" name="title" placeholder="Enter Title">
</div>
<div class="form-group fileForm">
<label >Image Files</label>
<div class="custom-file">
<input type="file" class="custom-file-input files" id="fileInput" multiple>
<label class="custom-file-label" data-browse="Browse"></label>
</div>
</div>
<div class="box">
</div>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
<script>
$(document).ready(function(e){
var regex =new RegExp("(.*?)\.(exe|sh|zip|alz|tiff)$");
// .*? : 줄 바꿈 문자를 제외한 모든 문자를 0개 이상 찾되, 최소 크기로 찾는다.
var maxSize = 10485760; //10MB
function checkExtension(fileName, fileSize){
if(fileSize>maxSize){
alert("파일 사이즈 초과")
return false;
}
if(regex.test(fileName)){ //RegExp.test() => 패턴이 있는지 없는지를 테스트하는데 목적
alert("해당 종류의 파일은 업로드 할 수 없습니다.")
return false;
}
return true;
}
$(".custom-file-input").on("change",function(){
var fileName = $(this).val().split("\\").pop();
//pop() : 배열에서 마지막 요소를 제거하고 그 요소를 반환합니다.
$(this).siblings(".custom-file-label").addClass("selected").html(fileName);
//siblings() : 자신을 제외한 형제 요소를 찾습니다.
//addClass() : 새로운 클래스를 추가(이미 가지고 있는 클래스는 추가되지 않습니다.)
//html() : 요소안의 내용을 지우고 새로운 내용을 넣습니다.
var formData = new FormData();
var inputFile = $(this);
var files = inputFile[0].files;
var append = false;
console.log(formData);
console.log(inputFile);
console.log(files);
console.log(append);
for(var i=0; i<files.length; i++){
if(!checkExtension(files[i].name, files[i].size)){
return false;
}
console.log(files[i]);
formData.append("uploadFiles",files[i]);
appended = true;
}
//upload를 하지 않는다.
if(!append){
return;
}
for(var value of formData.values()){
console.log(value);
}
//실제 업로드 부분
$.ajax({
url: '/uploadAjax',
processData: false,
contentType : false,
data : formData,
type : 'POST',
dataType : 'json',
success : function(result){
console.log(result);
},
error : function(jqXHR,textStatus,errorThrown){
conlose.log(textStatus);
}
});//$.ajax
});//end change event
}); //document ready
</script>
</th:block>
</th:block>
通常の処理
<form>
ラベルの下に、次のスタイルと<div>
を追加します.
<style>
.uploadResult {
width: 100%;
background-color: gray;
margin-top: 10px;
}
.uploadResult ul {
display: flex;
flex-flow: row;
justify-content: center;
align-items: center;
vertical-align: top;
overflow: auto;
}
.uploadResult ul li {
list-style: none;
padding: 10px;
margin-left: 2em;
}
.uploadResult ul li img {
width: 100px;
}
</style>
<div class="uploadResult">
<ul>
</ul>
</div>
function showResult(uploadResultArr){
var uploadUL = $(".uploadResult ul");
var str ="";
$(uploadResultArr).each(function(i,obj){
str += "<li data-name='" + obj.fileName + "' data-path='"+obj.folderPath+"' data-uuid='"+obj.uuid+"'>";
str + " <div>";
str += "<button type='button' data-file=\'" + obj.imageURL + "\' "
str += "class='btn-warning btn-sm'>X</button><br>";
str += "<img src='/display?fileName=" + obj.thumbnailURL + "'>";
str += "</div>";
str + "</li>";
});
uploadUL.append(str);
}
//실제 업로드 부분
$.ajax({
url: '/uploadAjax',
processData: false,
contentType : false,
data : formData,
type : 'POST',
dataType : 'json',
success : function(result){
console.log(result);
<---------추가---------->
showResult(result);
},
error : function(jqXHR,textStatus,errorThrown){
conlose.log(textStatus);
}
各画像は、ImageDTOに必要な属性を構成する
Reference
この問題について(応用[SPRING]映画/レビュー項目-(1)), 我々は、より多くの情報をここで見つけました https://velog.io/@jyyoun1022/SPRING영화리뷰-프로젝트-적용하기-1テキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol