ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Spring:Mapping,Repository,Autowired(DI),multipartFile
    JAVA 2021. 7. 26. 22:17
    public class Member {
    
    	private int no;
    	private String name;
    	private String post;
    	private String address;
    	private String detailaddress;
    	private String tel;
    	private String email;
    	private String id;
    	private String password;
    	private Date rdate;
    	private String state;
    	private String size;
    	byte[] profile;
    	MultipartFile profileFile;
    
    //중략...
    
    	public byte[] getProfile() {	
    		// 업로드한 파일을 먼저 MultipartFile 형으로 선언한 profileFile 멤버에 값을 넣고
    		// 이 byte[] 에 읽어온다.
    		try{
    			if(profileFile!=null) {return profileFile.getBytes();}
    		}catch(Exception e){
    			e.printStackTrace();
    		}
    		
    		return profile;
    	}
    	public void setProfile(byte[] profile) {
    		this.profile = profile;
    	}
    	
    	public MultipartFile getprofileFile() {
    		return profileFile;
    	}
    	public void setprofileFile(MultipartFile profileFile) {
    		this.profileFile = profileFile;
    	}
    	
    }

    Spring mvc

    Spring mvc 라이브러리
    1. MVC 설정 - viewResolver, Resource
    택 1
    1) XML 설정 : 예전부터 쓰던 방식 ( 나중에 알아는 봐야할 듯 )
    2) Class + Annotation 설정 : 디버깅이 가능하다.
    2. 빈 컨테이너(빈등록)
    빈 - 하나만 만들어놓고 일 시킬 수 있는 객체들 ( 상태가 없음 )
    1) BeanConfig 클래스 따로 만들어 @Bean 에 하나씩 설정하기(반환값, 메서드이름 전부 등록할 클래스 이름 )
    = DAO, Control 은 아니지만 하나만 만들어놓고 일 시킬 수 있는 상태가 없는 객체들을 여기에서 설정 ( 직접 만들지 않았고 주로 라이브러리 클래스 )

    2) @ComponentScan("패키지명") : MVC 설정한 클래스에 패키지단위로 한번에 @Bean 설정가능
    = DAO, Control 은 이걸로 한번에 설정됨 ( 직접 패키지안에 만든 클래스들 )

    현재 학원에서 쓰는 버전

    웹모듈 = 3.1

    스프링버전 = 5

    JRE 버전 = 1.8 ( 8버전 )

    @Controller
    class 클래스명{
      @RequestMapping(value="요청명", method=RequestMethod.POST)
      public void 컨트롤메서드(){}
    
      @RequestMapping(value="요청명", method=RequestMethod.GET)
      public void 컨트롤메서드(){}
    }
    @RequestMapping
    1. GET, POST 선택해 매핑하기
    (value = "요청명", method = RequestMethod.GET 또는 POST 방식 선택)

    @PostMapping, @GetMapping("요청명") 으로 바로 가능해졌다.

    이제 직접 실습해본 FrontControl 역할을 Spring 이 알아서 해준다. (코드는 보이지 않는다.)


    의존성 주입 ( Dependency injection )

    하나의 객체가 다른 객체의 의존성을 제공하는 테크닉이다.

    >> MvcConfig.java

    @Configuration
    @EnableWebMvc
    @ComponentScan(basePackages = "com.stone")
    public class MvcConfig implements WebMvcConfigurer {
    
    	@Override
    	public void configureViewResolvers(ViewResolverRegistry registry) {
    		registry.jsp("/WEB-INF/views/",".jsp");
    	
    	}
    	
    	@Override
    	public void addResourceHandlers(ResourceHandlerRegistry registry) {
    		// addResourceHandler = 모든 요청명 풀네임, addResourceLocations = 요청명 중 폴더명
    		registry.addResourceHandler("/img/*.png").addResourceLocations("/img/");
    		registry.addResourceHandler("/img/*.jpg").addResourceLocations("/img/");
    		registry.addResourceHandler("/js/*.js").addResourceLocations("/js/");
    	}
    }
    @Repository
    1. DAO 에 걸어줌으로서 spring 에서 알아서 미리 메모리에 하나 생성하라고 선언 = 의존성 객체( DI )
    하나 미리 생성해놓기 때문에 변화하지 않는 값 DAO, Control 이 각각 Repository, Controller 로 선언해 사용하는 것이다.
    VO 는 각 객체마다 달라야 하므로 Repository 로 선언 사용 불가하다.
    2. 인터페이스는 객체를 생성하지 못해 당연히 DI 가 되지 못한다. 구현한 클래스에 사용해야한다.
    @Autowired
    1. 어노테이션 밑에 '클래스명 객체명;' 만으로도 알아서 생성한 DI 가져옴.
    - Control 에서 DAO 사용할 때 DAO 를 DI 로 만들어 사용함.
    객체가 어떤 인터페이스를 구현했다면 변수형이 인터페이스여도 문제없이 DI 를 가져온다.(new 로 Spring 에서 올린애를 가져오는 느낌)

    컨트롤마다 DAO 사용한 부분확인해서 메서드밖, 멤버변수로 @Autowired 로 DI 가져오자.

    Spring 에서 업로드한 파일에 대한 설정하기 ( 아래 둘중 택1 이나 1번방식 채택)
    1번. web.xml 에 <multipart-config> 로 스프링에서 업로드한 파일을 가지고 있는 객체를 선언
    밑에 각 설정을 해놓음으로서 업로드시 계속 설정했던 것들을 생략 가능하게됨
    사용법은 https://www.baeldung.com/spring-file-upload 3. With Servlet 3.0 부분, 그리고 아래 설명예정
    2번. pom.xml 에 설치했던 기존의 servlets.com 의 cos 지우고 위의 라이브러리로 바꾸기
    사용법은 https://www.baeldung.com/spring-file-upload 2. Commons FileUpload 부분

    1 번 방법 정리

    >> web.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" id="WebApp_ID" version="3.1">
    	<!-- 스프링서블릿설정 -->
    	<servlet>
    		<servlet-name>dispatcher</servlet-name>
    		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    		<init-param>
    			<param-name>contextClass</param-name>
    			<param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value>			
    		</init-param>
    		<init-param>
    			<param-name>contextConfigLocation</param-name>
    			<param-value>
    				config.MvcConfig
    				config.BeanConfig
    			</param-value>	
    		</init-param>
    		<load-on-startup>1</load-on-startup>
    
            // 여기 추가!
    		<multipart-config>
    			<location>/upload</location>
    			<max-file-size>5242880</max-file-size>
    			<max-request-size>20971520</max-request-size>
    			<file-size-threshold>0</file-size-threshold>
    		</multipart-config>
    	</servlet>
    	
    	<servlet-mapping>
    		<servlet-name>dispatcher</servlet-name>
    		<url-pattern>/</url-pattern>
    	</servlet-mapping>	
    	
    	<!-- 필터 -->
    	<filter>
      		<filter-name>loginFilter</filter-name>
      		<filter-class>com.stone.mvc.env.LoginFilter</filter-class>
    	</filter>
      
    	<filter-mapping>
      		<filter-name>loginFilter</filter-name>
      		<url-pattern>/prepare_board.do</url-pattern>
      		<url-pattern>/add_board.do</url-pattern>
      		<url-pattern>/detail_member.do</url-pattern>
    	</filter-mapping>
    	
    </web-app>

    >> BeanConfig.java

    	@Bean
    	public StandardServletMultipartResolver multipartResolver() {
    	    return new StandardServletMultipartResolver();
    	}

     

    Spring 에서 업로드한 파일에 대한 설정하기: web.xml 방식
    전제사항
    1) 앞으로 form 에서 넘어오는 값들을 request.getParameter() 하지 않아도 Spring 이 html 태그의 name 속성값과 VO의 멤버변수명이
    같다면 Spring 이 알아서 짝지어준다. ( 해당 VO 를 컨트롤의 매개변수로 넣으면 자동 인식함 )
    2) File 은 Spring의 request 가 처리를 못하기 때문에 web.xml 에서 올려놓은 객체를 이용한다. ( 객체 설명은 아래에 )
    1. 위처럼 web.xml 에 먼저 객체 셋팅
    <multipart-config>: 스프링에서 업로드한 파일을 가지고 있는 객체
    <max-file-size>5242880</max-file-size> = 각각 개별 파일사이즈 (5MB)
    <max-request-size>20971520</max-request-size> = 한번에 들어올 수 있는 전체 파일 사이즈 (20MB)
    <file-size-threshold>0</file-size-threshold> = 메모리에서 가지고 있는 파일갯수 // 더 공부
    2. BeanConfig.java 에서 파일을 반환하는 컨트롤인 'StandardServletMultipartResolver' 빈으로 선언
    ( MvcConfig 에서 한번에 선언 불가, 내가 만든 패키지에 없고 어느 라이브러리에 있는 애라 이렇게 개별 선언필요)
    'StandardServletMultipartResolver' 가 아마 파일을 가지고 있는 'MultipartFile' 형으로 꺼내주는 컨트롤러 인듯 싶다.
    'MultipartFile' = web.xml 에 선언한 객체인 듯 싶다.
    3. 파일 값을 받을 VO 에 가서 byte[] 형으로 하나(현재 기존에있는거 사용), 'MultipartFile'형으로 하나 file을 담을 멤버변수를 만든다.
    4. MultipartFile 이 Control인 'StandardServletMultipartResolver' 을 통해 꺼내온 파일이 있다면 getBytes(); 로 byte[]형의 변수에게
    넘긴다. (db에서는 byte[] 로 받을 수 있기 때문에 바꿔준다.)
    5. 컨트롤러가 이 VO 를 사용시 매개변수에 넣으면 Spring 이 알아서
    객체 안을 살펴 멤버변수명과 input에서 넘어온 name 속성값을 매칭 시켜준다.
    단, MultipartFile 을 멤버변수로 가지고 있을 때는 @ModelAttribute 를 앞에 선언해줘야 한다.
    <multipart-config>
    <location>/upload</location>

    저 경로가 안잡히는 이유:
    eclipse webapp 경로와 tomcat 서버의 webapp 경로(=eclipse 복제해서 서버로 가져옴)가 실제로 달라서 eclipse 에서 아무리 만들어도
    서버가 돌아갈 때 tomcat 서버 아래의 webapp 경로를 찾는다.
    (원래 전엔 RealPath로 Eclipse 내부를 찾았지만 지금 RealPath 를 찾는 @ModelAttribute 는 tomcat 서버 아래를 찾는다.
    // Spring 어노테이션들은 DispatcherServlet 안에서 돌아가는 서버용인듯 )

    해결방법: tomcat 서버 아래 없다면서 떠있는 경로를 /upload 이전까지 복사한 후 들어가서 upload 폴더 만들기

    오늘의 어노테이션 정리

    1. @RequestMapping(value="요청명", method=RequestMethod.POST) : 요청매핑 method 정하기
    2. @GetMapping("요청명"), @PostMapping("요청명") : get 또는 post method 가 정해진 요청매핑
    3. @Repository @Autowired : (DI) DAO 를 빈으로 등록
    4. @ModelAttribute 는 매개변수에 VO가 MultipartFile 형의 멤버변수를 가지고 있다면 선언해줘야 한다.
    5. @RequestParam : input 의 name속성값과 매개변수명이 다를 경우 () 에 "name속성값" 을 넣어 매핑해줌
    또는 session 의 setAttribute 한 'key값' 과 매핑해줌
    - 속성 ( 사용시 기본형태인 @RequestParam("name속성값") 불가 )
    value : 원래 그냥 RequestParam("name속성값") 이였는데 아래와 같은 옵션들을 같이 쓸 경우 value="name속성값" 으로 기입해야한다.
    required : true = 안들어오면 오류 , false = 안들어오면 초깃값으로 떨어진다.(객체는 null, int 는 0)
    defaultValue : 초깃값을 바꾼다.

    사진이 많은 쇼핑몰(호텔) 의 경우

    기존방법은 회원 프로필 한번, 프로필사진 한번 총 두번 DB에 접근하느라 늦어졌지만

    이 방법으로 한번에 DB를 접근하여 사진까지 다 가져올 수 있다.

    >> pom.xml (라이브러리 하나 필요함)

    		<dependency>
    			<groupId>net.iharder</groupId>
    			<artifactId>base64</artifactId>
    			<version>2.3.9</version>
    		</dependency>

    >> 컨트롤러 (회원상세보기에서 실습함)

    @Controller
    public class 회원상세보기{
    	
    	@Autowired
    	IMemberDAO memberDAO;
    
    	@RequestMapping("detail_member2.do")
    	public ModelAndView process2(@RequestParam(value = "no", required=true, defaultValue = "-1")int 회원번호) {
    		ModelAndView mv = new ModelAndView();
    		
    		Member findedMember = memberDAO.findByNo(회원번호);
    			
    		mv.addObject("findedMember", findedMember);
    		
    		//그림을 글자로 바꿔 간다.
    		String profile = Base64.encodeBytes(findedMember.getProfile());
    		mv.addObject("profile", profile);
    		mv.setViewName("회원상세창2");
    
    		return mv;
    	}
    }

    >> view

    <body>
    
    <h1>회원상세</h1>
    프로필<img src="data:/jpg;base64, ${profile}"/><br>
    <button onclick="location.href='contents.do'">내용창으로</button>
    </body>

    data:/jpg;base64, (컴마까지 잘 쓰기!)

    'JAVA' 카테고리의 다른 글

    Spring:resolver  (0) 2021.07.26
    board,member(spring.ver1)  (0) 2021.07.26
    Spring, Tomcat Servers의xml파일정리  (0) 2021.07.26
    UML: ClassDiagram,SequenceDiagram, Servlet:Filter  (0) 2021.07.26
    로그인아웃, session  (0) 2021.07.26

    댓글

Designed by Tistory.