応用[SPRING]映画/レビュー項目-(1)


ファイルをアップロードしてムービーを登録し、ユーザーがムービーコメントを記録する例を作成します.
  • 映画の登録と修正ファイルアップロード機能を使用して映画ポスターなどを配置する.
  • メンバーは、既存のメンバーが存在すると仮定し、データベースに存在するメンバーを使用します.
  • 会員は、特定の映画閲覧ページで採点と自分の感想をコメントすることができます.
  • ブラウズ画面では、会員は記録されたコメント内容を変更/削除することができます.
  • 映画登録処理

  • コントローラパッケージは、ムービーコントローラクラスを作成します.
  • 映画登録用の「/movie/register」を追加します.
  • @Controller
    @Log4j2
    @RequestMapping("/movie")
    public class MovieController {
    
        @GetMapping("/register")
        public void register(){
            
        }
    
    }
  • テンプレートにムービーフォルダを追加して登録します.htmlを作成します.
  • <!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>
  • MovieDTO/MovieImageDTOクラスおよびMovieService
  • ムービーはエンティティークラスの処理を完了したので、DTOとサービス層のみが処理されます.
  • MovieDTOはMovieクラスに基づいて作成されます.
  • MovieDTOクラスの内部にアップロードファイルの情報が含まれている必要があるため、MovieImageDTOクラスを追加します.
  • @Data
    @Builder
    @NoArgsConstructor
    @AllArgsConstructor
    public class MovieDTO {
    
        private Long mno;
    
        private String title;
    
        @Builder.Default
        private List<MovieImageDTO> imageDTOList = new ArrayList<>();
        //화면에 영화 이미지들도 같이 수집해서 전달해야 하므로 내부적으로 리스트를 이용하여 수집합니다.
    }
  • 映画の画像については、MovieImageDTOは以前のUploadResultDTOと同じである.
  • @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 "";
        }
    }
  • プロジェクトにサービスパッケージを追加し、MovieServiceインタフェースとMovieServiceImplクラスを追加します.
  • のdtoEntity()が追加され、MovieオブジェクトとMovieImageオブジェクトのリストがMapタイプで処理されます.
  • 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();
        }
    }
  • MovieController MovieDTOを介してPOST方式で伝達するパラメータを収集するMovieServiceオブジェクトを呼び出すレジスタ()
  • .
    @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";
        }
    }
    処理表示
  • 添付ファイルの領域
  • 画面では、まず添付ファイルのアップロードを処理します.
  • このプロセスでは、画面上のアップロードファイルを同時に処理する必要があります.
  • register.htmlにファイル部分をアップロードするクラスは「custom-file-input」で、イベントの処理に使用できます.
  • 画面では、添付ファイルのアップロードによって変更イベントが処理され、ボタンなしでファイルの選択時に自動的に実行されます.
  • <!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>

    通常の処理
  • でアップロードすると、画面に島図領域を追加して島図を表示する必要があります.
  • register.htmldml <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>
  • Ajaxを呼び出すと、showResult()という個別の関数として処理されます.
  • register.htmlの一部を変更し、showResult()を呼び出します.
  • 
                    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に必要な属性を構成する
  • タグで構成される.