우선 첫번째 전제로 페이지 폼 태그에서


<form action="insert.me" method="POST" enctype="multipart/form-data">

<input type="file" name="photo">

</form>


과 같이 enctype="multipart/form-data"으로 데이터를 전송해야 한다.






두번째 전제로 라이브러리 다운로드


업로드 관련 라이브러리를 pom.xml에 추가하자( https://qdgbjsdnb.tistory.com/237 )




세번째 전제로 업로드 관련 서블릿 xml 설정들


    <!-- 파일 업로드를 하기 위해 bean 등록 -->
    <beans:bean class="org.springframework.web.multipart.commons.CommonsMultipartResolver" id="multipartResolver">
        <beans:property name="maxUploadSize" value="10000000"></beans:property>
    </beans:bean>


용량 10MB 이하만 등록가능 하기 때문에 10MB보다 조금 적게 max를 설정








구현


    @RequestMapping("insert.me")
    public String insertMember(Member m, Model model, HttpServletRequest request, @RequestParam(value = "photo", required = false) MultipartFile photo) {
        System.out.println("Member : " + m);
        System.out.println("photo : " + photo);
       
        String root = request.getSession().getServletContext().getRealPath("resources");
       
        String filePath = root + "\\uploadFiles";
       
        // 파일명 변경
        String originFileName = photo.getOriginalFilename();
        String ext = originFileName.substring(originFileName.lastIndexOf("."));
        String changeName = CommonUtils.getRandomString();
       
        try {
            photo.transferTo(new File(filePath + "\\" + changeName + ext));
           
            ms.insertMember(m);
           
            return "redirect:goMain.me";
           
        } catch (Exception e) {
            new File(filePath + "\\" + changeName + ext).delete();
           
            model.addAttribute("msg", "회원가입 실패!");
            return "common/errorPage";
        }
    }




주목할 부분은 빨간색 글씨로 입력


ext는 기존의 파일의 확장자를 따옵니다.


DB의 중복을 피하기위해 랜덤 String을 생성해 이름을 변경


photo.transferTo(new File(filePath + "\\" + changeName + ext)); 를 통해 저장


만약 DB 등록에 실패하면 new File(filePath + "\\" + changeName + ext).delete();로 저장된 파일 삭제






사용자가 View를 통해서 로그인 정보(ID, PW)를 입력하여 로그인을 요청했다는 가정하에 진행


Controller에 로그인 정보가 넘어왓을 때







위와 같은 구조로 순서는


View - Controller - try( Service - Dao ), catch(LoginException)


진행


Controller 데이터 처리는 저번 포스트와 같이 하면 된다. ( https://qdgbjsdnb.tistory.com/238 )


소개한 8가지 방법 중 아무거나 써도 된다.


이 중 7번째


@Controller
public class MemberController {

    @Autowired
    private MemberService ms;


    @RequestMapping("login.me")
    public String loginCheck(Member m, Model model, HttpSession session) {
        Member loginUser;
        try {
            loginUser = ms.loginMember(m);
           
            session.setAttribute("loginUser", loginUser);
           
            return "redirect:goMain.me";
        } catch (LoginException e) {
            model.addAttribute("msg", e.getMessage());
           
            return "common/errorPage";
        }
       
        return null;
    }

}




Member 타입 객체 loginUser는


Spring이 객체화 해 준 Service 인터페이스인 MemberService 타입 객체 ms의


loginMember 메소드를 이용하여 로그인 정보(ID, PW)를 넘긴다.




loginUser = ms.loginMember(m);의 loginMembe메소드나 그 하위 메소드에서


throw new LoginException을 하용하기 때문에 try catch문이 필요.





MemberService.java


public interface MemberService {

    Member loginMember(Member m) throws LoginException;

}

MemberServiceImpl.java


@Service

public class MemberServiceImpl implements MemberService {
    @Autowired
    private SqlSessionTemplate sqlSession;
    // 이렇게만 쓰면 Autowired로 생성되지 않기 때문에 xml에 따로 명시해야함
    // root-context.xml에서 진행
    
    @Autowired
    private MemberDao md;


    @Override
    public Member loginMember(Member m) throws LoginException {


        System.out.println(sqlSession.hashCode());


        Member loginUser = md.loginCheck(sqlSession, m);
        return loginUser;
    }

}




SqlSessionTemplate sqlSession은 DB를 연결해주는 라이브러리를 이용한 객체


저번에 설명한 대로 설정파일을 읽어 Spring에서 자동 생성한다. ( https://qdgbjsdnb.tistory.com/236 )


MemberDao md; 또한 컨트롤러에서 Service생성과 똑같이 생성된다.


이번엔 굳이 try catch를 사용하지 않고 throw를 사용






※참고 - 기존의 서블릿 방식으로 객체를 수작업으로 생성하면 .hashcode를


여러번 호출 하였을 때 값이 계속 바뀌는것을 확인 할 수 있다.


Spring에서는 Spring 컨테이너로 생성해준 객체의 .hash코드를


여러번 호출하면 매번 같은 값을 출력하는걸 확인할 수 있다.


이를 통해 같은 객체를 매번 새롭게 생성하는것이 아닌 재사용을 통해


메모리를 좀 더 효율적으로 사용하고 있다고 확인할 수 있다.






MemberDao.java


public interface MemberDao {

    Member loginCheck(SqlSessionTemplate sqlSession, Member m) throws LoginException;

}




MemberDaoImpl.java



@Repository
public class MemberDaoImpl implements MemberDao{

    @Override
    public Member loginCheck(SqlSessionTemplate sqlSession, Member m) throws LoginException {
        Member loginUser = sqlSession.selectOne("Member.loginCheck", m);
       
        System.out.println("Dao Member : " + loginUser);
       
        if (loginUser == null) {
            throw new LoginException("로그인 정보가 존재하지 않습니다.");
        }
       
        return loginUser;
    }

}


MemberDaoImple에서는 SqlSessionTemplat과 myBatis 메소드를 이용해서


DB를 조회해온다.


메소드 명, 사용법은 저번에 설명한 mybatis와 완전 같음.


( https://qdgbjsdnb.tistory.com/228?category=733892, https://qdgbjsdnb.tistory.com/229?category=733892 )


sqlSession.selectOne("Member.loginCheck", m);


조회 결과를 통해 try catch




mybatis와 DB 관련 라이브러리를 이용하기 때문에 pom.xml에 라이브러리 추가는 필수이다.( https://qdgbjsdnb.tistory.com/237 )








LoginException.java의 경우는 간단하게 다음과 같다.


public class LoginException extends Exception{
    public LoginException(String msg) {
        super(msg);
    }
}







이와 같이 Spring을 이용하면 이와같이 코드의 길이가 매우 짧아지고


자동으로 해주는것(프로그래머가 아닌 Spring Container가)이 많아져 편리하다.


특히 누구든 코드 분석하기가 훨씬 쉬워져 다른 사람과 작업에 좋다.


협업에 알맞지만 Spring 구조와 설정 사용법 등 너무 복잡하고 어렵다는 단점이 있다.





다음과 같은 Ajax 요청이 있다고 하자.


    <script type="text/javascript">
        function duplicationCheck() {
            var userId = $("#userId").val();
           
            $.ajax({
                url:"duplicationCheck.me",
                type:"post",
                data:{userId:userId},
                success:function(data){
                    /* alert(data); */
                    console.log(data);
                    console.log(data.userId);
                },
                error:function(status){
                    console.log(status);
                }
               
            });
           
            return false
        }
    </script>





duplicationCheck.me로 ID가 중복되는지 체크해달라는 요청이다.


Controller, Service, Dao 중 Service, Dao 사용방법은 단순 DB 조회로 생략


Controller에서 4가지 방법을 확인해보자.


기본적으로 pom.xml을 통해서 관련 라이브러리가 추가되었음을 전제로 진행 ( https://qdgbjsdnb.tistory.com/237?category=733876 )


또한 관련 라이브러리 추가로 인한 xml 설정


servlet.xml, 서블릿 xml에 다음 태그들을 추가




    <!-- jsonView 설정 -->
    <beans:bean id="jsonView" class="net.sf.json.spring.web.servlet.view.JsonView"></beans:bean>
    <!-- beanNameViewResolver는 없는 자원에 대해 논리적 이름을 가지고 view를 지정한다. -->
    <beans:bean id="viewResolver" class="org.springframework.web.servlet.view.BeanNameViewResolver">
        <beans:property name="order" value="1"></beans:property>
    </beans:bean>
    
    <!-- 메세지 컨버터 추가 -->
    <!-- 자바 객체를 자바스크립트 객체로 바꿔주는 역할을 한다. -->
    <beans:bean id="jacksonMessageConverter" class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"></beans:bean>
    <beans:bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
        <beans:property name="messageConverters">
            <beans:list>
                <beans:ref bean="jacksonMessageConverter"></beans:ref>
            </beans:list>
        </beans:property>
    </beans:bean>


xml 설정은 이것으로 마치고 구현



1. 스트림을 이용, 다른 툴은 이용하지 않고 기본 기능을 통해서 값 전달



    // 1. 스트림을 이용한 ajax 처리
    @RequestMapping("duplicationCheck.me")
    public void duplicationCheck(@RequestParam String userId, HttpServletResponse response) {
        System.out.println(userId);
       
        try {
            response.getWriter().print(false);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }



2. ObjectMapper를 이용, 잭슨 라이브러리를 사용


ObjectMapper라는 객체를 생성하여 메소드를 이용해서 객체 자체를 전달



    // 2. ObjectMapper를 이용한 ajax
    @RequestMapping("duplicationCheck.me")
    public void duplicationCheck(@RequestParam String userId, HttpServletResponse response) {
        // 잭슨 라이브러리를 사용함
        ObjectMapper mapper = new ObjectMapper();
       
        Member m = new Member();
       
        m.setUserId(userId);
       
        try {
            response.getWriter().print(mapper.writeValueAsString(m));
        } catch (JsonGenerationException e) {
            e.printStackTrace();
        } catch (JsonMappingException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }




결과 Data 값은 위와 같이 출력된다.


배열이나 객체 타입이 아닌 String 형으로 나열되어 나온다.








3. jsonView를 이용, Controller의 ModelAndView 방식과 유사


반환 타입이 ModelAndView



    // 3. jsonView를 사용한 방식
    @RequestMapping("duplicationCheck.me")
    public ModelAndView duplicationCheck(String userId, ModelAndView mv) {
       
        Member m = new Member();
        m.setUserId(userId);
       
        mv.addObject("member", m);
       
        mv.setViewName("jsonView");
       
        // 한글의 경우 인코딩 처리를 해야함
       
        return mv;
    }




결과는 이와같이 오브젝트 타입으로 안에 배열 형식으로 객체가 담겨있다.





4. @ResponseBody를 이용, HashMap을 통해 원하는값을 보냄




    // 4. @ResponseBody를 이용한 ajax
    @RequestMapping("duplicationCheck.me")
    public @ResponseBody HashMap<String, Object> duplicationCheck(@RequestParam String userId, HttpServletResponse response) {
       
        HashMap<String, Object> hmap = new HashMap<String, Object>();
       
        hmap.put("userId", userId);
       
        return hmap;
    }






결과는 위와 같다.


HashMap을 통해서 원하는 값만 간편하게 보내면 된다.








4가지 방식을 보면 사용방법은 모두 쉽다.


문제는 반환되는 형식이 어떠하냐인데 마음에 드는 방법에 익숙해지거나


상황에 맞는 방법을 골라서 하면 될거같다.





+ Recent posts