이사후 게속 샤워나 세수 또는 따뜻한 물을 쓸때마다 물때가 게속 생깁니다.ㅠㅠ


이를 해결하기위해 나노글라스 나노코팅 셀프욕실코팅-나노엔 을 구입했습니다. 

http://smartstore.naver.com/nanon/products/2415719720?NaPm=ct%3Djh2rur93%7Cci%3Dcheckout%7Ctr%3Dppc%7Ctrx%3D%7Chk%3D2cb9895fb2803ac94d36406db58046865cba6644

가격은 현재 2만2천원대로 할인중입니다.


자 그럼 배송 온 내용을 볼까요?

박스를 까니 설명서가 나옵니다.

요약하면 리무버를 바른후, 그냥 코팅제를 바르면 된다고하는데 냄새가 좀 독하니 마스크 쓰고 작업하세요.


그리고 나온 구성물들은 다음과 같습니다.

리무버, 코팅제, 스펀지, 마른 타월 2개, 장갑 1개

잘써서 거울에 코딩 하시면됩니다.

코팅 중입니다...

작업시간은 대략 20분?

정도 걸린거같습니다. 코팅제바른후 24시간동안 물이 튀면안되니 주의하시면됩니다.

다들 구매하셔서 잘 사용하시길.



'LIFE > ETC' 카테고리의 다른 글

아비셀 어성초 천연비누  (0) 2018.05.14
이지캔 27L 쓰레기통  (0) 2018.05.14
컬러빈 분리수거 쓰레기통  (0) 2018.05.14
신혼 선물 받은 그릇들과 식기들  (0) 2018.05.11
신혼 선물 받은 후라이팬 및 냄비  (0) 2018.05.11

요즘은 소나 재밌게합니다.

곧 레벨 10되면 또 딴거할예정입니다.

'GAME > HEROES OF THE STORM' 카테고리의 다른 글

히오스 배치 결과  (0) 2018.05.15

예전챕터에서 에러를 처리하는 Exceptional handler(@Controller Advice)를 배웠을것이다.

당시챕터에선 공통적인 에러처리를 하였지 정상적인 에러처리는 안하였다.


이번엔 헤더값을 가지고 우리가만든 인터셉터로 커스텀익스셉션을 만들어주자

일단 exception이라는 패키지를 만들어주자. 그리고 그안에 CustomException이라는 익스셉션을 만들어주자

 package com.pratice.project.exception;


public class CustomException extends RuntimeException {


private static final long serialVersionUID = 5166839488988493842L;


public CustomException(final String msg){

super(msg);  

}

}


 

 


보면알다시피 에러 메시지를 정의해준다. 그리고 여기서 보시다시피 런타임 익스셉션을 상속받아 

@ControllerAdvice에서 컨트롤 할 수 있게 해주었다.


다음은 인터셉터에서 헤더값을 가지고와서 에러처리를 해주자.

 package com.pratice.project.interceptor;


import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;


import org.springframework.web.servlet.HandlerInterceptor;

import org.springframework.web.servlet.ModelAndView;


import com.pratice.project.exception.CustomException;


public class CommonInterceptor implements HandlerInterceptor  {



@Override

public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object Obj) throws Exception {

// TODO Auto-generated method stub

String id = request.getHeader("id");

if(id!=null&&id.length()>0){

System.out.println("id가 널이 아닙니다! 정상로직!");

}

else if(id==null||id.length()==0){

System.out.println("id가 널입니다! 에러처리!");

throw new CustomException("id가 비어있습니다");

}

return true;

}

@Override

public void postHandle(HttpServletRequest request, HttpServletResponse response, Object Obj, ModelAndView mv)

throws Exception {

// TODO Auto-generated method stub

System.out.println("posthandle");

}

@Override

public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object Obj, Exception ex)

throws Exception {

// TODO Auto-generated method stub

}



}


 


보시다시피 request.getheader값으로 헤더를 가지고오고 id값이 널이아니거나 길이가 0보다크면 정상로직이라고 선언했다.

그것이아니고 id가 널이거나 id길이가 0이면 널처리를 하고throw CustomException으로 넘겨주었다


이 Custom Exception은 ControllerAdvice로 넘어가고


@ExceptionHandler(Exception.class)

public STAT handleException(Exception e) {

STAT stat=new STAT();

stat.setStat("fail");

stat.setCause(e.getMessage());

return stat;

}


위와같은 로직으로 리턴된다. 이제 API를 호출해보자.



에러를 호출할수 있도록 id를 아무값도없이 헤더를 세팅하였다.


다음으로 send를 눌러보자.



보이는가 완벽하게 처리되었다.

이런식으로 커스텀 익스셉션을 처리하면된다.


좀더 커스텀하게하는방법은

ControolerAdvice를 아래와 같이 바꾸면된다.

 package com.pratice.project;


import org.springframework.web.bind.annotation.ControllerAdvice;

import org.springframework.web.bind.annotation.ExceptionHandler;

import org.springframework.web.bind.annotation.RestController;


import com.pratice.project.exception.CustomException;

import com.pratice.project.model.STAT;


@RestController

@ControllerAdvice

public class AnnotationExceptionHandler {

@ExceptionHandler(CustomException.class)

public STAT CustomExceptionhandleException(Exception e) {

STAT stat=new STAT();

stat.setStat("fail");

stat.setCause("커스텀 익스셉션발생!:"+e.getMessage());

return stat;

}

@ExceptionHandler(Exception.class)

public STAT handleException(Exception e) {

STAT stat=new STAT();

stat.setStat("fail");

stat.setCause(e.getMessage());

return stat;

}

}

 


이러면 아래와 같이 확인할 수 있다.




'DEV > SPRING' 카테고리의 다른 글

Rest Service 구현[9]  (0) 2018.05.11
Rest Service 구현[8]  (0) 2018.05.11
Rest Service 구현[7]  (0) 2018.05.11
Rest Service 구현[6]  (0) 2018.05.11
Rest Service 구현[5]  (0) 2018.05.11

전처리 후처리를 할 수 있는 인터셉터를 만들어줘보자.

스프링은 전처리 후처리를 담당 할 수 있는 인터셉터란 녀석이있다.

먼저 WEB-INF의 servlet-context를변경해주자

 <?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"

xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xmlns:context="http://www.springframework.org/schema/context"

xsi:schemaLocation="http://www.springframework.org/schema/mvc 

http://www.springframework.org/schema/mvc/spring-mvc.xsd

http://www.springframework.org/schema/beans 

http://www.springframework.org/schema/beans/spring-beans.xsd

http://www.springframework.org/schema/context 

http://www.springframework.org/schema/context/spring-context.xsd">


<!-- DispatcherServlet Context: defines this servlet's request-processing 

infrastructure -->


<!-- Enables the Spring MVC @Controller programming model -->

<mvc:annotation-driven />


<context:component-scan base-package="com.pratice.project"

use-default-filters="false">

<context:include-filter type="annotation"

expression="org.springframework.stereotype.Controller" />

</context:component-scan>


<!-- Handles HTTP GET requests for /resources/** by efficiently serving 

up static resources in the ${webappRoot}/resources directory -->

<mvc:resources mapping="/resources/**" location="/resources/" />


<mvc:interceptors>

<mvc:interceptor>

<mvc:mapping path="/**" />

<bean class="com.pratice.project.interceptor.CommonInterceptor" />

</mvc:interceptor>

</mvc:interceptors>



<!-- Resolves views selected for rendering by @Controllers to .jsp resources 

in the /WEB-INF/views directory -->

<bean

class="org.springframework.web.servlet.view.InternalResourceViewResolver">

<property name="prefix" value="/WEB-INF/views/" />

<property name="suffix" value=".jsp" />

</bean>

<!-- <context:component-scan base-package="com.pratice.project"></context:component-scan> -->



</beans>



보면 알다시피 /**란 뜻은  prefix인 project를 포함한 모든 url매핑의 전처리를 뜻한다 이부분을 유저가 정의해서 따로 인터셉터를 만들수도있다. 다음은 인터셉터 클래스인 CommonInterceptor를 만들어주자.물론이전에 interceptor란 패키지를 만들어주자

 package com.pratice.project.interceptor;


import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;


import org.springframework.web.servlet.HandlerInterceptor;

import org.springframework.web.servlet.ModelAndView;


public class CommonInterceptor implements HandlerInterceptor  {



@Override

public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object Obj) throws Exception {

// TODO Auto-generated method stub

System.out.println("prehandle");

return true;

}

@Override

public void postHandle(HttpServletRequest request, HttpServletResponse response, Object Obj, ModelAndView mv)

throws Exception {

// TODO Auto-generated method stub

System.out.println("posthandle");

}

@Override

public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object Obj, Exception ex)

throws Exception {

// TODO Auto-generated method stub

}



}


 


prehandle은 전처리를 의미한다. posthandle은 후처리를 의미하고 마지막 aftercomplete은 로직이 종료됬을때를의미한다.

그리고 파라미터를 보면 request와 response가 있는것을 확인 할 수 있다. 전처리 후처리에 출력문을 적어두었다.

여기서 주의할점은 전처리에 true를 리턴해야만 정상적으로 전처리가 실행된다.


정상적이라면 아래와같은 구조를 띄게된다.



그다음 할일은 서버를 돌려서 아무 API나 호출해보자 



그다음 출력창을 확인해보자.




정상적으로 전처리 후처리가 되는것을 확인할 수있다.



'DEV > SPRING' 카테고리의 다른 글

Rest Service 구현[10]  (0) 2018.05.11
Rest Service 구현[8]  (0) 2018.05.11
Rest Service 구현[7]  (0) 2018.05.11
Rest Service 구현[6]  (0) 2018.05.11
Rest Service 구현[5]  (0) 2018.05.11

전챕터에서 뭔가한가지 문제가있다.


@Override

public STAT addUser(User user) {

// TODO Auto-generated method stub

STAT stat = new STAT();

try {

mapper.addUser(user);

stat.setStat("success");

return stat;

} catch (Exception e) {

stat.setStat("fail");

stat.setCause(e.getMessage());

return stat;

}

}


@Override

public UserList getUserList() {

// TODO Auto-generated method stub

UserList userlist = new UserList();

try {

userlist.setStat("success");

List<User> list=mapper.getUserList();

userlist.setUserList(list);

return userlist;

} catch (Exception e) {

userlist.setStat("fail");

userlist.setCause(e.getMessage());

return userlist;

}

 

 

 

 }


바로 이부문이다 보시다시피 두개다 에러처리가 되어있는데 catch부분이 동일한것을 볼 수 있다 setstat은 어쩔 수 없다고 쳐도

cause는 똑같은 문이 두번이나 반복된다.


이것을 어떻게 처리 할 수 있을까? 스프링은 @ControllerAdvice라는 에러 공통처리하는 부분을 만들어 줄 수 있다.

AnnotationExceptionHandler하나만들어주자 위치는 com.pratice.project에 만들어주자


 package com.pratice.project;


import org.springframework.web.bind.annotation.ControllerAdvice;

import org.springframework.web.bind.annotation.ExceptionHandler;

import org.springframework.web.bind.annotation.RestController;


import com.pratice.project.model.STAT;


@RestController

@ControllerAdvice

public class AnnotationExceptionHandler {

@ExceptionHandler(Exception.class)

public STAT handleException(Exception e) {

STAT stat=new STAT();

stat.setStat("fail");

stat.setCause(e.getMessage());

return stat;

}

}


 


내용만봐도 공통적인 사항들을 뺀부분이 보이지않는가?

그리고 자세히보면 맨위에 RestController 애노테이션이 추가되어있는것을 알 수 있다.

이말은 json으로 리턴해주겠다는것이다.


그다음 Impl를 바꾸어주자

 package com.pratice.project.service.impl;


import java.util.List;


import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.stereotype.Service;


import com.pratice.project.dao.IGetDao;

import com.pratice.project.model.Name;

import com.pratice.project.model.STAT;

import com.pratice.project.model.User;

import com.pratice.project.model.UserList;

import com.pratice.project.service.TestService;


@Service

public class TestServiceImpl implements TestService {


@Autowired

private IGetDao mapper;


@Override

public Name getName(String name) {

// TODO Auto-generated method stub

Name Testreturn = mapper.selectName(name);

return Testreturn;

}


@Override

public User getUser(String id) {

// TODO Auto-generated method stub

User user = mapper.selectUser(id);

return user;

}


@Override

public STAT addUser(User user) {

// TODO Auto-generated method stub

STAT stat = new STAT();

mapper.addUser(user);

stat.setStat("success");

return stat;

}


@Override

public UserList getUserList() {

// TODO Auto-generated method stub

UserList userlist = new UserList();

userlist.setStat("success");

List<User> list = mapper.getUserList();

userlist.setUserList(list);

return userlist;


}


}



보면 중복되던 try catch문이 사라진것을 알 수 가 있다.


이제 restclient를 실행해보자.



정상동작하는것을 알 수있다.

'DEV > SPRING' 카테고리의 다른 글

Rest Service 구현[10]  (0) 2018.05.11
Rest Service 구현[9]  (0) 2018.05.11
Rest Service 구현[7]  (0) 2018.05.11
Rest Service 구현[6]  (0) 2018.05.11
Rest Service 구현[5]  (0) 2018.05.11

리스트를 구현해보자.


알다시피 get method로 현재까지 구현한내용들을 보면 전부 단일 row를 구해서 json으로 리턴시켜준다 

이제 데이터베이스의 있는 모든 내용들을 리턴시켜주어보자


일단 모델객체를 만들어주자

 package com.pratice.project.model;


import java.util.List;


import com.fasterxml.jackson.annotation.JsonInclude;

import com.fasterxml.jackson.annotation.JsonInclude.Include;

import com.fasterxml.jackson.annotation.JsonProperty;

import com.fasterxml.jackson.annotation.JsonPropertyOrder;


@JsonPropertyOrder({"stat","cause","userList"})

public class UserList {

@JsonProperty("stat")

@JsonInclude(Include.NON_NULL)

private String stat;

@JsonProperty("cause")

@JsonInclude(Include.NON_NULL)

private String cause;

@JsonProperty("userList")

@JsonInclude(Include.ALWAYS)

private List<User> userList;


public String getStat() {

return stat;

}


public void setStat(String stat) {

this.stat = stat;

}


public String getCause() {

return cause;

}


public void setCause(String cause) {

this.cause = cause;

}


public List<User> getUserList() {

return userList;

}


public void setUserList(List<User> userList) {

this.userList = userList;

}


}


잘보면 리스트는 유저들의 목록을 받아오는 필드고 나머지는 지난챕터에서 배운 에러처리를 위한 항목인걸 알 수 있다.



다음으로 dao인터페이스를 만들어주자

 package com.pratice.project.dao;


import java.util.List;


import com.pratice.project.model.Name;

import com.pratice.project.model.User;


public interface IGetDao {

public Name selectName(String name);

public User selectUser(String userID);

public void addUser(User user);

public List<User> getUserList();

}



user로 나오는 리스트들을 받는 다는 의미의 getUserList 인터페이스를 선언해주었다. 이제

쿼리문을 짜주자


 <?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE mapper

  PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"

  "http://mybatis.org/dtd/mybatis-3-mapper.dtd">




<mapper namespace="com.pratice.project.dao.IGetDao">



<select id="selectName" parameterType="String" resultType="name">

 <![CDATA[

 SELECT UserName

         FROM usertbl

         WHERE UserName = #{name}

        ]]>

</select>


<select id="selectUser" parameterType="String" resultType="user">

 <![CDATA[

 SELECT *

         FROM usertbl

         WHERE UserID = #{userID}

        ]]>

</select>


<insert id="addUser" parameterType="user">

 <![CDATA[

insert into userTbl(UserID,UserName,UserAge,Phone,Comment) values 

(#{userID},#{userName},#{userAge},#{phone},#{comment});

   ]]>

</insert>

<select id="getUserList" resultType="user">

 <![CDATA[

 SELECT *

         FROM usertbl

   ]]>

</select>

</mapper>

 


쿼리를 보면 user클래스로 리턴해주는것을 알수 있는데 여기서좀 의문이 들텐데. 어떻게 저 쿼리가 리스트로 보내지는 의문이 들것이다. 이것은 마이바티스가 row수가 1이상을 넘어가면 그 객체를 리스트로 자동으로 리턴시켜주는것이다. 


이제 다음으로 서비스 인터페이스에 우리가 사용할 함수를 선언해주자.

 package com.pratice.project.service;


import com.pratice.project.model.Name;

import com.pratice.project.model.STAT;

import com.pratice.project.model.User;

import com.pratice.project.model.UserList;


public interface TestService {

public Name getName(String name);

public User getUser(String id);

public STAT addUser(User user);

public UserList getUserList();

}


 


그리고 구현부를 만들어주자

 package com.pratice.project.service.impl;


import java.util.List;


import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.stereotype.Service;


import com.pratice.project.dao.IGetDao;

import com.pratice.project.model.Name;

import com.pratice.project.model.STAT;

import com.pratice.project.model.User;

import com.pratice.project.model.UserList;

import com.pratice.project.service.TestService;


@Service

public class TestServiceImpl implements TestService {


@Autowired

private IGetDao mapper;


@Override

public Name getName(String name) {

// TODO Auto-generated method stub

Name Testreturn = mapper.selectName(name);

return Testreturn;

}


@Override

public User getUser(String id) {

// TODO Auto-generated method stub

User user = mapper.selectUser(id);

return user;

}


@Override

public STAT addUser(User user) {

// TODO Auto-generated method stub

STAT stat = new STAT();

try {

mapper.addUser(user);

stat.setStat("success");

return stat;

} catch (Exception e) {

stat.setStat("fail");

stat.setCause(e.getMessage());

return stat;

}

}


@Override

public UserList getUserList() {

// TODO Auto-generated method stub

UserList userlist = new UserList();

try {

userlist.setStat("success");

List<User> list=mapper.getUserList();

userlist.setUserList(list);

return userlist;

} catch (Exception e) {

userlist.setStat("fail");

userlist.setCause(e.getMessage());

return userlist;

}

}


}


 


다른 구현부랑 차이가있다. 일단 지난 챕터에서 사용하던 try캐치문이 들어갔다. 그리고 mapper를 객체로 바로 주입하는게 아니라 일단 리스트형태로 가지고 온 후, 그 list를 set해서 선언한 모델객체인 userlist 주입한다. 나머지는 동일하다.


이제 api를 등록하기위해 컨트롤러를 만들어주자

 package com.pratice.project.controller;


import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;


import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.web.bind.annotation.RequestBody;

import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.web.bind.annotation.RequestMethod;

import org.springframework.web.bind.annotation.RequestParam;

import org.springframework.web.bind.annotation.RestController;


import com.pratice.project.model.Name;

import com.pratice.project.model.STAT;

import com.pratice.project.model.User;

import com.pratice.project.model.UserList;

import com.pratice.project.service.TestService;


@RestController

public class TestController {


@Autowired

TestService testservice;


@RequestMapping(value = "/test/rest", method = RequestMethod.GET)

public Name getName(HttpServletRequest request, HttpServletResponse response,

@RequestParam(value = "name") String name) {

Name rt = testservice.getName(name);

return rt;

}


@RequestMapping(value = "/user", method = RequestMethod.GET)

public User getUser(HttpServletRequest request, HttpServletResponse response,

@RequestParam(value = "userID") String userID) {

User rt = testservice.getUser(userID);

return rt;

}


@RequestMapping(value = "/adduser", method = RequestMethod.POST)

public STAT addUser(HttpServletRequest request, HttpServletResponse response, @RequestBody User user) {

STAT stat = testservice.addUser(user);

return stat;


}

@RequestMapping(value = "/userlist", method = RequestMethod.GET)

public UserList getUserList(HttpServletRequest request, HttpServletResponse response) {

UserList userlist = testservice.getUserList();

return userlist;


}

}

 


Res tclient를 url에 맞추어 설정해주자 물론 메서드는 GET이다.



정상적으로 뜨는가? 그렇다면 리스트를 리턴시켜준것이다.



'DEV > SPRING' 카테고리의 다른 글

Rest Service 구현[9]  (0) 2018.05.11
Rest Service 구현[8]  (0) 2018.05.11
Rest Service 구현[6]  (0) 2018.05.11
Rest Service 구현[5]  (0) 2018.05.11
Rest Service 구현[4]  (0) 2018.05.11

adduser이란 api를 똑같은 설정으로 다시 호출해보라.



아마도  아래 리스폰스에 어마어마한 긴 에러가 뜨게 될것이다. 왜 에러가뜨는걸까?

이유는 userID라는 컬럼이 기본키로 설정되있기때문에 중복허용을 하지 않기때문이다.


근데 리스폰스에 에러문을 보니 뭔가 답답하지않은가? 원인도파악하기힘들고 정말 서비스를 사용하는 유저가 API를 호출했을때

저런 화면이나 텍스트를 보면 어떤반응을할까?

[이 서비스는 개판이네...]

이런생각을 가지게될것이다.


또한 추가적으로 생각했을때. insert가 성공했을때 , 뭔가 성공했다고 혹시 response를 날려주었나? 그렇지않다. 이렇게 api를 짜게 되면

클라이언트[안드로이드나 웹페이지]는 이게 성공했는지 실패했는지 알기가 힘들다. 그리고 성공후에 클라이언트에서 특정이벤트를 한다면 더더욱 오리무중에 빠지게된다. 즉

클라이언트 -> 서버로 통신할때 서버는 클라이언트가 호출한 결과를 알려주어야한다.


이렇게 하는 처리를 에러처리라고한다. 

에러를 컨트롤하는 기능을 스프링에서 제공해주긴하는데 그것은 나중에 심화학습 챕터에서 알아보고 현재는 간단하게

에러를 처리하는 방식을 배워보자. 즉 try catch문으로 말이다.


일단 에러가 발생하든 안하든 리턴을 시켜주는 객체가필요하다 즉 모델이 필요하다

모델패키지에 STAT란 자바클래스를 하나 만들어주자

 package com.pratice.project.model;


import com.fasterxml.jackson.annotation.JsonInclude;

import com.fasterxml.jackson.annotation.JsonProperty;

import com.fasterxml.jackson.annotation.JsonInclude.Include;


public class STAT {

@JsonProperty("stat")

@JsonInclude(Include.NON_NULL)

private String stat;

@JsonProperty("cause")

@JsonInclude(Include.NON_NULL)

private String cause;


public String getStat() {

return stat;

}


public void setStat(String stat) {

this.stat = stat;

}


public String getCause() {

return cause;

}


public void setCause(String cause) {

this.cause = cause;

}


}


 


간단하다. stat은 이 api가 성공했을지 실패했을지를 담을 필드고 나머지 cause는 에러가 발생했을때만 나타나게할것이다.

알다시피 @JsonInclude(Include.NON_NULL) 걸려있기때문에 데이터가없으면 json 객체에 보여지지않는다.


자 이제 기존 서비스 인터페이스를 조금 바꿔보자.

 package com.pratice.project.service;


import com.pratice.project.model.Name;

import com.pratice.project.model.STAT;

import com.pratice.project.model.User;


public interface TestService {

public Name getName(String name);

public User getUser(String id);

public STAT addUser(User user);

}


 

서비스의 리턴형태를 STAT로 바꾸었다.

이제 addUser의 구현부를 바꾸어보자

 package com.pratice.project.service.impl;


import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.stereotype.Service;


import com.pratice.project.dao.IGetDao;

import com.pratice.project.model.Name;

import com.pratice.project.model.STAT;

import com.pratice.project.model.User;

import com.pratice.project.service.TestService;


@Service

public class TestServiceImpl implements TestService{


@Autowired

private IGetDao mapper;

@Override

public Name getName(String name) {

// TODO Auto-generated method stub

Name Testreturn = mapper.selectName(name);

return Testreturn;

}

@Override

public User getUser(String id) {

// TODO Auto-generated method stub

User user=mapper.selectUser(id);

return user;

}


@Override

public STAT addUser(User user) {

// TODO Auto-generated method stub

STAT stat =new STAT();

try{

mapper.addUser(user);

stat.setStat("success");

return stat;

}catch(Exception e){

stat.setStat("fail");

stat.setCause(e.getMessage());

return stat;

}

}


}


 

내용이 좀 길어졌긴했지만 반드시 필요한내용이다. 

stat를 new로써주고 객체를 만들어주고 try catch문으로 감싸주었다

에러가 발생하지않으면 setStat으로 성공이라는 텍스트를 객체에 주입시켜주고 stat자체를 리턴시켜준다

하지만 만약 중복에러 또는 다른 에러가 발생하면 fail이라는 텍스트를 객체에 주입시키고 cause에 에러메시지를 주입하고 stat를 리턴시켜준다.


이제 컨트롤러를 바꿀 차례다.

 package com.pratice.project.controller;


import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;


import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.web.bind.annotation.RequestBody;

import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.web.bind.annotation.RequestMethod;

import org.springframework.web.bind.annotation.RequestParam;

import org.springframework.web.bind.annotation.RestController;


import com.pratice.project.model.Name;

import com.pratice.project.model.STAT;

import com.pratice.project.model.User;

import com.pratice.project.service.TestService;


@RestController

public class TestController {


@Autowired

TestService testservice;


@RequestMapping(value = "/test/rest", method = RequestMethod.GET)

public Name getName(HttpServletRequest request, HttpServletResponse response,

@RequestParam(value = "name") String name) {

Name rt = testservice.getName(name);

return rt;

}


@RequestMapping(value = "/user", method = RequestMethod.GET)

public User getUser(HttpServletRequest request, HttpServletResponse response,

@RequestParam(value = "userID") String userID) {

User rt = testservice.getUser(userID);

return rt;

}


@RequestMapping(value = "/adduser", method = RequestMethod.POST)

public STAT addUser(HttpServletRequest request, HttpServletResponse response, @RequestBody User user) {

STAT stat = testservice.addUser(user);

return stat;


}

}

 

간단하다 STAT stat으로 addUser에서 나오는 객체를 받아서 리턴한다.

컨트롤러에서 리턴하니 json형태로 리턴되게된다.


실제 RESTCLIENT를 실행해보자

아래와같이 새로운값을 Send 해보자


send를 눌러보자


성공했다는 리스폰스가 뜨게된다. 

여기서 다시한번 똑같은 값을 Send하게되면...



실패가 뜨고 중복됬다고 친절하게 설명글까지 뜨게된다.


만약 클라이언트가 이 api를 호출하게되면 성공이되면 특정 이벤트가 발생되게 바꿀수있고

실패한다면 이벤트가발생안되고 특정에러가 발생했다고 알람창을 띄어주게 해줄수 있을것이다.


다음챕터는 리스트에 좀더 알아보도록하겠다.






'DEV > SPRING' 카테고리의 다른 글

Rest Service 구현[8]  (0) 2018.05.11
Rest Service 구현[7]  (0) 2018.05.11
Rest Service 구현[5]  (0) 2018.05.11
Rest Service 구현[4]  (0) 2018.05.11
Rest Service 구현[3]  (0) 2018.05.11

트랜잭션을 처리하는 aop를 context로 선언해서 auto로 관리해보고

insert api를 만들어줘보자.


알다시피 트랜잭션은 데이터베이스의 처리하는 단위이다. 즉 데이터베이스의 내용을 커밋해주는 역할도하며,

이 트랜잭션은 뭔가 데이터가 정상적이지못하거나 웹서버가 문제가 있어 중간에 죽으면

insert되던것을 롤백을 해야하는 임무도 더러있다.


현재 우리의 코드에서는 트랜잭션을 처리하는 부분이 존재하지않다.

이때문에 insert 과정중에 크리티컬 에러가 생겨도 롤백을 하지않는다. 이문제는 서비스단에서

엄청 큰문제를 초래 할 수 있다. 데이터는 정말 중요하다. 


그래서 트랜잭션을 여러가지방법으로 처리할수 있게 스프링에서 제공해주지만 내가써본바로는 aop만큼

편한방법을 찾지 못하였다. aop에 대해서 모른다면 스프링에대해서 좀더 공부해보길 추천드린다.


aop로 전체 서비스 객체에 트랜잭션을 걸 수가 있다. 그리고 따로 트랜잭션처리를 안해도 문제가 생기면 알아서 rollback까지

해준다.


자 이제 시작해보자. 일단 처음 해야할작업은 context-transaction.xml를 만드는것이다.

 <?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xmlns:aop="http://www.springframework.org/schema/aop"

xmlns:tx="http://www.springframework.org/schema/tx"

xsi:schemaLocation="http://www.springframework.org/schema/beans 

http://www.springframework.org/schema/beans/spring-beans.xsd

http://www.springframework.org/schema/tx 

http://www.springframework.org/schema/tx/spring-tx.xsd

http://www.springframework.org/schema/aop 

http://www.springframework.org/schema/aop/spring-aop.xsd">


<tx:annotation-driven />

<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">

<property name="dataSource" ref="dataSource"/>

</bean>

<tx:advice id="txAdvice" transaction-manager="txManager">

<tx:attributes>

<tx:method name="get*" read-only="true" />

   <tx:method name="add*" propagation="REQUIRED" />

<tx:method name="modify*" propagation="REQUIRED" />

<tx:method name="remove*" propagation="REQUIRED" />

</tx:attributes>

</tx:advice>

<aop:config>

<aop:pointcut id="requiredTx" expression="execution(* com.pratice.project.service.impl.*Impl.*(..))"/>

<aop:advisor advice-ref="txAdvice" pointcut-ref="requiredTx" />

</aop:config>

</beans>


 


txManager는 dataSource를 트랜잭션 메니저가 트랜잭션을 처리하겠다는 의미고 txAdvice는 txManager에서 설정된 데이터소스에 접근하는 트랜잭션 중에 메서드 명중에 앞글자를 따서 select ,add,modify,remove등이 앞으로오는 메서드가있으면 select 같은경우 read only만 해주고 나머지는 propagation="REQUIRED" 로 트랜잭션 처리를 하겠다는 뜻이다. 즉 값이 변화가생기면 commit을 해주거나 에러가생기면 롤백도 해준다는것이다.


마지막으로 aop에 특정 service 패키지내에 Impl로 끝나는 클래스들을 포인트컷을 걸어두고 advice에 txAdvice를 걸어주면 끝난다.


정상적으로됐다면 이제 트랜잭션처리는 끝난것이다.


간단하지않은가? 

이제 저 메서드의 해당하는 api를 추가만 해주면된다. insert에 해당하는 내용을 한번 만들어보자.

지금까지 전부 get로 했지만 이번에는 POST로 한번 짜보도록해보자.


먼저 IGetDao의 내용을 추가해주자.

 package com.pratice.project.dao;


import com.pratice.project.model.Name;

import com.pratice.project.model.User;


public interface IGetDao {

public Name selectName(String name);

public User selectUser(String id);

public void addUser(User user);

}


 보다시피 addUser이라는 메서드가 트랜잭션 관리하는 txAdvice랑 일치한다. add가 붙어있다. 파라미터는 user그자체를 받고 그 user객체를 insert하겠다는 의미이다. 


이제 쿼리를 작성해주자.

 <?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE mapper

  PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"

  "http://mybatis.org/dtd/mybatis-3-mapper.dtd">




<mapper namespace="com.pratice.project.dao.IGetDao">



<select id="selectName" parameterType="String" resultType="name">

 <![CDATA[

 SELECT UserName

         FROM usertbl

         WHERE UserName = #{name}

        ]]>

</select>


<select id="selectUser" parameterType="String" resultType="user">

 <![CDATA[

 SELECT *

         FROM usertbl

         WHERE UserID = #{userID}

        ]]>

</select>


<insert id="addUser" parameterType="user">

 <![CDATA[

insert into userTbl(UserID,UserName,UserAge,Phone,Comment) values 

(#{userID},#{userName},#{userAge},#{phone},#{comment});

   ]]>

</insert>

</mapper>

 

insert문이 추가된것이보인다. 여기서 몇가지 주의할점이있다. parametertype를 클래스 형태로 받으면 굳이 따로 변화할 필요없이 #{필드명}을 쓰면 알아서 클래스 객체의 있는 정보를 가지고와서 쓸수 있다. 단! 여기서 필드명의 첫글자는 소문자로 해주어야한다. 이것은 마이바티스 규약 사항처럼 보이는데 대문자로 하면 인식을 못하니 꼭 주의해야한다. 


그리고 보시다시피 클래스 User 객체의 필드들의 이름과 database의 컬럼이름이 똑같은것[단! 클래스 User객체의 필드들의 앞글자는 소문자이다.]을 알 수 있다. 이점을 항상 유의하면서 코드와 쿼리를 작성하기를 바란다.


이제 쿼리가 작성됐다면 Service interface를 정의해주자.

 package com.pratice.project.service;


import com.pratice.project.model.Name;

import com.pratice.project.model.User;


public interface TestService {

public Name getName(String name);

public User getUser(String id);

public void addUser(User user);

}


 

이제 Impl 실행부에 구현을 적어주자

 package com.pratice.project.service.impl;


import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.stereotype.Service;


import com.pratice.project.dao.IGetDao;

import com.pratice.project.model.Name;

import com.pratice.project.model.User;

import com.pratice.project.service.TestService;


@Service

public class TestServiceImpl implements TestService{


@Autowired

private IGetDao mapper;

@Override

public Name getName(String name) {

// TODO Auto-generated method stub

Name Testreturn = mapper.selectName(name);

return Testreturn;

}

@Override

public User getUser(String id) {

// TODO Auto-generated method stub

User user=mapper.selectUser(id);

return user;

}


@Override

public void addUser(User user) {

// TODO Auto-generated method stub

mapper.addUser(user);

}


}


 


보시다시피 별내용이 없다 단순히 mapper.addUser한 내용이고 파라미터로는 user를 받겠다는 소리다.


여기까지 됐다면 아까처럼 controller를 추가할차례다.

 package com.pratice.project.controller;


import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;


import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.web.bind.annotation.RequestBody;

import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.web.bind.annotation.RequestMethod;

import org.springframework.web.bind.annotation.RequestParam;

import org.springframework.web.bind.annotation.ResponseBody;

import org.springframework.web.bind.annotation.RestController;


import com.pratice.project.model.Name;

import com.pratice.project.model.User;

import com.pratice.project.service.TestService;


@RestController

public class TestController {


@Autowired

TestService testservice;

@RequestMapping(value = "/test/rest", method = RequestMethod.GET)

public Name getName(HttpServletRequest request, HttpServletResponse response,

@RequestParam(value="name")String name) {

Name rt=testservice.getName(name);

return rt;

}

@RequestMapping(value = "/user", method = RequestMethod.GET)

public User getUser(HttpServletRequest request, HttpServletResponse response,

@RequestParam(value="userID")String userID) {

User rt=testservice.getUser(userID);

return rt;

}

@RequestMapping(value = "/adduser", method = RequestMethod.POST)

public void addUser(HttpServletRequest request, HttpServletResponse response,@RequestBody User user) {

testservice.addUser(user);

}

}


기존 컨트롤러 메서드랑 좀 틀린 부분이 보이지않는가? 바로 @RequestBody User user가 아래붙어있는데 이부분은 리퀘스트로 오는부분을 json형태로 받을 수 있도록한것이며 json으로 받은데이터를 user객체에 대입해준것이다. 그리고 선언한 서비스 객체의 addUser를 해준것이다.


이제 정상적으로 동작하는지 RestClient로 확인해보자


위와같이 insert api란 것을 새로 save하고 url를 적어주고 Post를 선택해주자.

Post를 선택하면 아래와같이 json을 작성하는 부분이 출력된다. 그부분에 해당과 같이 작성해주자.



 { "userID":"goo92",

  "userName":"goomankim",

  "userAge":"27",

  "phone":"010...",

  "comment":"gogo"

}

 

보다시피 클래스 user객체의 필드명과 대소문자가 정확하게 일치한다! 정확히 일치해야 값을 얻어올 수 있으니 반드시 주의하기바란다.


이제 send를 눌러보자. 아마 아래 아무런 데이터 반응이 없다고 뜨면 성공적이다(이부분은 다음 챕터에서 보완을 하는 내용을 기재하겠다)


이제 데이터베이스의 내용을 확인해보자(select * fromusertbl)




위와같이 데이터베이스에 정확하게 들어간것을 확인 할 수 있다.


다음챕터에서는 에러처리를 하는 리턴문과 여러 데이터들을 한꺼번에 리스트형태로 리턴하는것을 기재할예정이다.



'DEV > SPRING' 카테고리의 다른 글

Rest Service 구현[7]  (0) 2018.05.11
Rest Service 구현[6]  (0) 2018.05.11
Rest Service 구현[4]  (0) 2018.05.11
Rest Service 구현[3]  (0) 2018.05.11
Rest Service 구현[2]  (0) 2018.05.11

처음 할 내용은 json 포맷을 변경하는 방법부터 알아보자

일단 모델객체인 Name.java를 변경 해주어야한다.


package com.pratice.project.model;


import com.fasterxml.jackson.annotation.JsonInclude;

import com.fasterxml.jackson.annotation.JsonProperty;

import com.fasterxml.jackson.annotation.JsonPropertyOrder;

import com.fasterxml.jackson.annotation.JsonInclude.Include;


@JsonPropertyOrder({"name"})

public class Name {

@JsonProperty("name")

@JsonInclude(Include.NON_NULL)

private String userName;


public String getUserName() {

return userName;

}


public void setUserName(String name) {

this.userName = name;

}


}



(여기서 전챕터에서 말하지않은 내용이있는데 UserName이 userName으로 바뀐것을 알 수가 있다. 알다시피 데이터 컬럼과 필드값이 일치해야하는데 일치하는조건이 첫글자는 소문자로 써주어야한다[컬럼이 대문자여도!!] 그래야 정상적으로 다른 설정 부분을 쓸 수 있다.) 


일단 클래스위에 있는 @JsonPropertyOrder 는 json의 필드 출력순서를 정해준다. 지금은 필드가 username뿐이지만 실제 서비스에서는 많은 필드를 가지고 있기때문에 어떤것이 먼저 출력될지 정해주어야할때가 많다. 그때 사용되게된다.


두번째 @JsonProperty 는 출력되는 포맷을 결정해준다. 

원래 출력형태를 기억하는가?


필드:밸류가 userName:"yoonjiwon" 이지만

이와같이 JsonProperty 선언하면 name:"yoonjiwon"으로 출력되게된다.


또한 추가적으로 @JsonInclude(Include.NON_NULL)은 null로 데이터가 없을때는 필드를 노출안하겠다는뜻이다.

지금은 필드가 하나지만 필드가 2개일때 만약 1개의 필드는데이터가 있고 1개의 필드가 데이터가없다면

저 설정을 안하면 2개의 필드가 동시에 노출된다.

이런식으로 말이다.

name:"heemin",

  age:null        }


null나오는 방법은 매우 안좋고 클라이언트가 인식하는데도 문제가 있기떄문에 노출이 한개만되게끔 설정해주는것이다.


이상태에서 이제 다시 호출해보면


우리가 변경한 필드가 정상적으로 노출되는것을 알수 있다.


자 다음으로 테스트 컨트롤러를 변경해서 url파라미터로 받아서 함수를 실행시켜보자.

그전에 mysql workbench에 테스트 케이스를 더만들기 위해 insert를 좀더 해놓자.

 insert into userTbl(UserID,UserName,UserAge,Phone,Comment) values 

('heemin87','heeminkim','29','010-7194-0000','hello my name is Heemin');


insert into userTbl(UserID,UserName,UserAge,Phone,Comment) values 

('heejin92','heejinkim','27','010-0000-0000','hello my name is Heejin');


기존 테스트 컨트롤러는 문제가 있다.

바로 개발자가 테스트를 하기위해서 파라미터를 강제로 import시키고있다.

실제로 보게되면은

public Name getName(HttpServletRequest request, HttpServletResponse response) {

Name rt=testservice.getName("yoonjiwon");

return rt;

}

아래와 같이 testservice.getName의 개발자가 알고있는 이름을 대입해서 강제로 테스트 한것을 알 수 있다.

이부분을 이제 url 파라미터로 받아서 변경하는 부분을 실행해보자.


코드는 이런식으로 변경해준다.

 package com.pratice.project.controller;


import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;


import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.web.bind.annotation.RequestMethod;

import org.springframework.web.bind.annotation.RequestParam;

import org.springframework.web.bind.annotation.RestController;


import com.pratice.project.model.Name;

import com.pratice.project.service.TestService;


@RestController

public class TestController {


@Autowired

TestService testservice;

@RequestMapping(value = "/test/rest", method = RequestMethod.GET)

public Name getName(HttpServletRequest request, HttpServletResponse response,

@RequestParam(value="name")String name) {

Name rt=testservice.getName(name);

return rt;

}

}


보다시피 @RequestParam 이 추가 된것을 알수가 있다.

url뒤에 name 파라미터를 붙여서 보내줘서 그 파라미터를 문자형 변수 name으로 받아서 값을 넘겨주는 방식으로 바뀌었다.


이제 RestClient를 바꾸어서 호출해보자.


보다시피 뒤에 파라미터를 보내기위해 ? 가 붙었고 name이란 파라미터에 값을 heeminkim으로 해준것이다.

이제 send를 보내게 되면.



정상적으로 이름이 뜨는것을 알 수가 있다.


이 전체적인것을 응용하면 좀더 잘 알 수 있게 변경할수 있다.


일단 model 클래스를 추가해주자.

User.java를 모델패키지에 추가시켜주자.

 package com.pratice.project.model;


import com.fasterxml.jackson.annotation.JsonInclude;

import com.fasterxml.jackson.annotation.JsonProperty;

import com.fasterxml.jackson.annotation.JsonPropertyOrder;

import com.fasterxml.jackson.annotation.JsonInclude.Include;


@JsonPropertyOrder({"userID","userName","userAge","phone","comment"})

public class User {

@JsonProperty("userID")

@JsonInclude(Include.NON_NULL)

private String userID;

@JsonProperty("userName")

@JsonInclude(Include.NON_NULL)

private String userName;

@JsonProperty("userAge")

@JsonInclude(Include.NON_NULL)

private String userAge;

@JsonProperty("phone")

@JsonInclude(Include.NON_NULL)

private String phone;

@JsonProperty("comment")

@JsonInclude(Include.NON_NULL)

private String comment;


public String getUserID() {

return userID;

}


public void setUserID(String userID) {

this.userID = userID;

}


public String getUserName() {

return userName;

}


public void setUserName(String userName) {

this.userName = userName;

}


public String getUserAge() {

return userAge;

}


public void setUserAge(String userAge) {

this.userAge = userAge;

}


public String getPhone() {

return phone;

}


public void setPhone(String phone) {

this.phone = phone;

}


public String getComment() {

return comment;

}


public void setComment(String comment) {

this.comment = comment;

}


}



다음으로 IGetDao에 데이터를 가지고올 인터페이스를 정의하자. 파라미터는 이미 name으로 받아봤으니 이제 id로 받아보자.

 package com.pratice.project.dao;


import com.pratice.project.model.Name;

import com.pratice.project.model.User;


public interface IGetDao {

public Name selectName(String name);

public User selectUser(String userID);

}



다음으로 sql config에 객체를 좀 쓰기 편하게 하기위하여 정의시켜주자.[sqlmap/sql-mapper-config.xml]

 <?xml version="1.0" encoding="UTF-8" ?>

<!DOCTYPE configuration

  PUBLIC "-//mybatis.org//DTD Config 3.0//EN"

  "http://mybatis.org/dtd/mybatis-3-config.dtd">

  

<configuration>

<typeAliases>

<typeAlias alias="name" type="com.pratice.project.model.Name"/>

<typeAlias alias="user" type="com.pratice.project.model.User"/>

</typeAliases>

</configuration>



다음으로 인터페이스를 구현하기위한 쿼리문을 작성하자.

 <?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE mapper

  PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"

  "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

  

  

  

  <mapper namespace="com.pratice.project.dao.IGetDao">



<select id="selectName" parameterType="String" resultType="name">

 <![CDATA[

 SELECT UserName

         FROM usertbl

         WHERE UserName = #{name}

        ]]>

</select>

<select id="selectUser" parameterType="String" resultType="user">

 <![CDATA[

 SELECT *

         FROM usertbl

         WHERE UserID = #{userID}

        ]]>

</select>

  </mapper>



이제 이로직을 처리할 서비스 로직을 추가해주기위해 TestService에 인터페이스를 추가 시켜주자.

 package com.pratice.project.service;


import com.pratice.project.model.Name;

import com.pratice.project.model.User;


public interface TestService {

public Name getName(String name);

public User getUser(String id);

}



이제 실행부인 TestServiceImpl에 해당 메서드를 구현해주자

 package com.pratice.project.service.impl;


import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.stereotype.Service;


import com.pratice.project.dao.IGetDao;

import com.pratice.project.model.Name;

import com.pratice.project.model.User;

import com.pratice.project.service.TestService;


@Service

public class TestServiceImpl implements TestService{


@Autowired

private IGetDao mapper;

@Override

public Name getName(String name) {

// TODO Auto-generated method stub

Name Testreturn = mapper.selectName(name);

return Testreturn;

}

@Override

public User getUser(String id) {

// TODO Auto-generated method stub

User user=mapper.selectUser(id);

return user;

}


}


이제 컨트롤러를 추가해서 api를 만들어서 최종적으로 마무리한다.

 package com.pratice.project.controller;


import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;


import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.web.bind.annotation.RequestMethod;

import org.springframework.web.bind.annotation.RequestParam;

import org.springframework.web.bind.annotation.RestController;


import com.pratice.project.model.Name;

import com.pratice.project.model.User;

import com.pratice.project.service.TestService;


@RestController

public class TestController {


@Autowired

TestService testservice;

@RequestMapping(value = "/test/rest", method = RequestMethod.GET)

public Name getName(HttpServletRequest request, HttpServletResponse response,

@RequestParam(value="name")String name) {

Name rt=testservice.getName(name);

return rt;

}

@RequestMapping(value = "/user", method = RequestMethod.GET)

public User getUser(HttpServletRequest request, HttpServletResponse response,

@RequestParam(value="userID")String userID) {

User rt=testservice.getUser(userID);

return rt;

}

}


이제 RestClient 에서 우리가만든 api가 정상적으로 호출되는지 확인해보자.

먼저 save as new로 새로운 api를 등록해주고


이와같이 등록해주고 다시 save버튼을 누르고 overwrite를 해주자.

등록이되었다면 send를 눌러줘보자.




정상적으로 나오는가?

이 일련의 과정들이 API추가하는 모든것들을 의미한다.

즉 자신이 원하는 API는 이런식으로 추가하면된다.



'DEV > SPRING' 카테고리의 다른 글

Rest Service 구현[6]  (0) 2018.05.11
Rest Service 구현[5]  (0) 2018.05.11
Rest Service 구현[3]  (0) 2018.05.11
Rest Service 구현[2]  (0) 2018.05.11
Rest Service 구현[1]  (0) 2018.05.11

해당포스트를 읽기전에 반드시

http://dev-khm.tistory.com/21



데이터베이스를 만들기를 바란다.해당 챕터는 데이터 베이스와 연관되서 데이터를 가지고오는 챕터기때문에 선행학습이 필요하다.

우리는 알다시피 스프링컨텍스트 파일을 따로 관리 할 수 있게끔 분리시켰다.


이제 그 스프링컨텍스트에 mysql에 접속하기 위한 설정파일 두개를 만들것이다.

context-datasource.xml

context-mapper.xml를 만들것이다

먼저 데이터소스는 데이터베이스의 접근하기 위한 정보들을 설정한다고보면되며

mapper는 마이바티스란 오픈소스를 이용해. slq쿼리문과 연결시켜주는 역할을 한다고보면된다.


세세한 설명은 차분히 설명을하며 진행하도록하겠다.

먼저 지난번에 만들어주었던 spring 폴더에 context-datasource.xml 만들어주자.


 <?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance

xmlns:p="http://www.springframework.org/schema/p"

xsi:schemaLocation="http://www.springframework.org/schema/beans 

http://www.springframework.org/schema/beans/spring-beans.xsd">


<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">

<property name="driverClassName" value="com.mysql.jdbc.Driver" />

<property name="url" value="jdbc:mysql://localhost:3306/app_data" />

<property name="username" value="root" />

<property name="password" value="1234" />

</bean>

</beans>


해당내용으로 작성을 해주자. 간단하게 설명하면 url은 로컬호스트로 돌리는 내 mysql에 로컬호스트로 돌리는 스프링 웹서버가 접근하겠다는 소리고 접근할때 3306으로 접근하고 app_data라는 스키마에 접근하겠다는소리다.


유저와 패스워드는 처음 mysql를 설치할때 설정한 값을 적용하면된다.

정상적으로 적었다면 아래와 같이 설정된다.



 

자이제 context-mapper.xml를 만들어주자.

 <?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance

xmlns:tx="http://www.springframework.org/schema/tx

xmlns:util="http://www.springframework.org/schema/util"

xmlns:aop="http://www.springframework.org/schema/aop"

xmlns:context="http://www.springframework.org/schema/context"

xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd

http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd 

http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd

http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd

http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">


<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">

<property name="dataSource" ref="dataSource" />

<property name="configLocation" value="classpath:/sqlmap/sql-mapper-config.xml" />

<property name="mapperLocations" value="classpath:/sqlmap/mappers/*.xml" />

</bean>

<bean id="mapper" class="org.mybatis.spring.mapper.MapperScannerConfigurer">

<property name="basePackage" value="

  com.pratice.project.dao

" />   

 <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory" />

</bean>


</beans>

 


설정이 조금많지만 복잡하지않다. 전부다 마이바티스 라이브러리를 사용하여 내부기능설정을 지정한다.

먼저 sqlSessionFacetory같은경우 데이터베이스에 접근하기위한 정보는 context-datasource.xml에 선언한 내용을 그대로 가지고 사용한다 실제로 보면 ref="dataSource"로 되어있는것을 알 수 있다. configLocation은 sql문을 쓸때 클래스path가 긴것을 개발자가 보기 쉽게하기 위해 사용된다. 이부분은 챕터를 보다보면 이해가될것이다. 그다음 mapperLocation은 우리가 만든 sql문의 접근위치를 이야기해준다


간단히 이야기하면 datasource정보를 접근해서 데이터베이스에 접근하고 mapperlocations에 위치한 쿼리문을 통해서 쿼리한다라는 의미다. 편의를위해서 쿼리문에서 configLocation에 위치한 설정파일로 쿼리를 실행할 때 도움을주고..


자 여기까지했으면 조금 의문이 들수 있다. 그럼 코드상에선 어떻게 접근을하는가?

그방법은 바로 아래에 있다.

mapper라는 bean을 하나 선언해준다. 이 mapper빈을 자바 코드내에서 autowired해서 가지고온다. 물론 autowired할때 mapper아래 설정한 property name="basePackage"에서 설정한 패키지에 존재하는 인터페이스만 접근하겠다는소리다.




인터페이스는 챕터를 진행하면서 만들것이다. 마지막에 정리가될것이다.

이제 다음으로 configLocation에 위치하는 /sqlmap/sql-mapper-config.xml를 만들어주자

sqlmap은 spring 폴더와 동일한위치에 만들어주면된다.

 <?xml version="1.0" encoding="UTF-8" ?>

<!DOCTYPE configuration

  PUBLIC "-//mybatis.org//DTD Config 3.0//EN"

  "http://mybatis.org/dtd/mybatis-3-config.dtd">

  

<configuration>


<typeAliases>

<typeAlias alias="name" type="com.pratice.project.model.Name"/>

</typeAliases>

</configuration>



내용은 정말간단하다. 우리가 만든Name 클래스를 간단하게 name이라는 명칭으로 접근하겠다는의미다. 이해가 안될수도있는데 만약 컨피그를 안사용하면 저 path.클래스 길게 일일히 쳐주어야한다.

다음으로 sqlmap안에 mappers라는 폴더를 만들어주고 그안에 query.xml이라는것을 만들어 간단한 셀렉트문을 만들어주자.


 <?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE mapper

  PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"

  "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

  

  

  

  <mapper namespace="com.pratice.project.dao.IGetDao">



<select id="selectName" parameterType="String" resultType="name">

 <![CDATA[

  SELECT UserName

         FROM usertbl

         WHERE UserName = #{name}

        ]]>

</select>

  </mapper>


이query.xml이 여러분들이 사용하게될 sql문을 적을장소이다.

mappernamespce는 내가만든 dao를 인터페이스를 의미한다.(곧만들것이다)

그리고 그 인터페이스의 정의된 메서드의 selectName의 쿼리는 아래에 나와있다.


이것을 보면 뭔가 보이지않는가? service인터페이스랑 형태만 다른뿐이지

쿼리자체가 실행부가된다고보면된다 즉 impl class implements service interface 가 그냥 query.xml implements dao interface가 된다고보면된다.


그리고 아래부분을 보시면 인터페이스에서 정의한 함수들을 구현하기위해 작성된 쿼리를 볼수 있다. 파라미터를 받겠다는 의미고 파라미터는 String으로 받겠다는 의미다. 그리고 resultType는 아까 config에서 설정한 Name class타입으로 객체를 리턴시키겠다는 것이다.


즉 쿼리를 실행하면 Name이란 객체로 데이터를 set시키고 리턴시키겠다는의미이다. 

정상적으로 세팅했다면 아래와같이 세팅이된다.




이제 dao를 만들어보자.. 그전에 한가지 바꿀부분이있다 모델클래스의 String name과 get,set 함수 이름을 좀 바꾸어야한다.

왜냐하면 DB컬럼과 이름을 똑같이해줘야 데이터를 받아올때 매핑될수 있다.

아래와 같이 바꿔주자.

 package com.pratice.project.model;


public class Name {

private String UserName;


public String getUserName() {

return UserName;

}


public void setUserName(String name) {

this.UserName = name;

}


}


이제 dao 패키지를 만들어주자. 그리고 패키지 안에 인터페이스를 만들어주자. 인터페이스명은 <mapper namespace="com.pratice.project.dao.IGetDao">선언한대로 IGetDao로 선언해주자.


그후..

<select id="selectName" parameterType="String" resultType="name">

 <![CDATA[

  SELECT UserName

         FROM usertbl

         WHERE UserName = #{name}

        ]]>

</select>

위에 선언한대로 selectName이란 함수를 만들어주고 name를 파라미터로 받아주는 메서드를 선언하자

 package com.pratice.project.dao;


public interface IGetDao {

public Name selectName(String name);

}


 


어떤가? 이제 이해가되지않는가? 구현부는 즉 implement영역은 쿼리, 인터페이스 영역은 IGetDao로 되어있다.

정상적으로 됬다면 위와같이 보일것이다.



이제 Service영역을 바꾸어보자.

 package com.pratice.project.service.impl;


import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.stereotype.Service;


import com.pratice.project.dao.IGetDao;

import com.pratice.project.model.Name;

import com.pratice.project.service.TestService;


@Service

public class TestServiceImpl implements TestService{


@Autowired

private IGetDao mapper;

@Override

public Name getName(String name) {

// TODO Auto-generated method stub

Name Testreturn = mapper.selectName(name);

return Testreturn;

}

}


어떤가? 아까  context-mapper.xml 설정했던 mapper를 기억하는가?

그 mapper를 bean 객체를 불어오는것이다. IGetDao란 형태의 인터페이스로 불러오라는것이다.

아까내용은 다음과같다

<bean id="mapper" class="org.mybatis.spring.mapper.MapperScannerConfigurer">

<property name="basePackage" value="

  com.pratice.project.dao

" />   

 <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory" />

</bean>


위의내용에서 선언된 mapper를 가지고오되 dao안에 있는 패키지안에 인터페이스를 사용해서 가지고온것이다.

그리고 이런부부은 우리가만든 sql문이랑 연결되는것이다.


이제 디비 컬럼값을 조회하기위해서 TestController를 바꾸어주자

 package com.pratice.project.controller;


import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;


import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.web.bind.annotation.RequestMethod;

import org.springframework.web.bind.annotation.RestController;


import com.pratice.project.model.Name;

import com.pratice.project.service.TestService;


@RestController

public class TestController {


@Autowired

TestService testservice;

@RequestMapping(value = "/test/rest", method = RequestMethod.GET)

public Name getName(HttpServletRequest request, HttpServletResponse response) {

Name rt=testservice.getName("yoonjiwon");

return rt;

}

}



보면 바뀐부부은 이름을 조회하기 위해서 컬럼에 있는값들을 집어넣어주었다.

즉 로직을 설명하면

컨트롤러 url 매핑 -> 서비스 객체 오토와이어로 가지고오고 -> 서비스 impl 실행 -> mapper 객체 오토와이어로 가지고오고 mapper는 설정된 패키지 내에있는 인터페이스 형태로 가지고오게되고 -> mapper는 설정된 database로 연결되며 sqlmap에 선언된 쿼리문으로 연결된다. 


이런식이고 인터페이스와 sqlmap에 쿼리가 연결된다만 특별히 기억하면된다.

이제 이결과를 Rest client에서 실행하게되면.



위와같이 데이터베이스를 조회한 결과물이 나오게된다.


다음챕터는 json 포맷변화 컨트롤러의 파라미터를 받아서 조회하는 방법 까지 할예정이다. 조금더 여유가 있다면 트랜잭션처리까지 할예정이다.



'DEV > SPRING' 카테고리의 다른 글

Rest Service 구현[5]  (0) 2018.05.11
Rest Service 구현[4]  (0) 2018.05.11
Rest Service 구현[2]  (0) 2018.05.11
Rest Service 구현[1]  (0) 2018.05.11
Spring restful service 참고사이트  (0) 2018.05.11

+ Recent posts