앞의 글을 착실히 수행했다면 study4_1 프로젝트는 다음과 같을것이다.
pom.xml과 web.xml, 그리고 spring 폴더의
appconfig.properties,context-*.xml, mvc-servlet.xml 파일들은 만들어져있을 것이다.
그리고 프로젝트 세팅도 되어있을 것이다.
이전글 https://brilliantdevelop.tistory.com/88을 참고하자.
(context는 context-main, context-datasource.xml로 나누었다.)
이 설정파일들에 맞춰서 java파일들과 그 외기타파일들을 만들것이다.
복사
https://brilliantdevelop.tistory.com/category/jsp 의 글들을 진행했다면 다음과 같은
프로젝트가 완성되었을 것이다.
1. src
config폴더에는 요청 url 관련 매핑설정들이 있지만
spring에서는 DispatcherServlet이 담당하므로 복사할 필요가 없다.
먼저 mybatis 파일들을 복사해주자.
context-datasource.xml에 보면 sqlSessionFactory 빈에서 설정한대로 mybatis-config.xml파일과
mapper파일들을 위치시켜야한다.
<bean id="dataSource"
class="org.apache.commons.dbcp2.BasicDataSource"
destroy-method="close">
<property name="driverClassName"
value="#{util['jdbc.driverClassName']}" />
<property name="url"
value="#{util['jdbc.url']}" />
<property name="username" value="#{util['jdbc.username']}" />
<property name="password" value="#{util['jdbc.password']}" />
<property name="defaultAutoCommit" value="#{util['jdbc.defaultAutoCommit']}" />
</bean>
<!-- SqlSession setup for MyBatis Database Layer -->
<bean id="sqlSessionFactory"
class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="configLocation"
value="/WEB-INF/classes/mybatis/mybatis-config.xml" />
<property name="mapperLocations"
value="/WEB-INF/classes/mybatis/mapper/*.xml" />
</bean>
복사된 mybatis 파일들
freeBoard_temp는 mybatis처음 설정할 때 임시로 연결이 잘되었나
확인했던 파일이니까 필요없다. 삭제하자.
여기서 mybatis-config.xml을 보자. 이전에는 이 파일을 읽어서 DB에 연결하기때문에
DB연결관련 코드와 mapper 관련 설정 코드가 있었지만,
Spring에서는 mybatis 연결할 때 sqlSessionfactoryBean안에 다 정의 되어 있기 때문에
mybatis-config.xml에는 DB연결관련코드와 mapper 관련 설정코드가 필요없다. 삭제해주자.
수정된 mybatis-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>
<settings>
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
</configuration>
이번엔 java파일들을 복사하자.
filter,servlet패키지는 삭제하고, util패키지에서는 CookieUtils만 남기자.
Spring에서는 LoginCheck기능을 interceptor를 이용해서 구현할거고
servlet은 기본적으로 Spring에서 다 제공하기 떄문에 우리가 직접 만들 필요는 없다.
util에서 ConnectionProvider, MybatisSqlSessionFactory를 삭제하는 이유는
context-datasource.xml에서 sqlSessionFactory 빈등록을 했는데
이 빈이 DB연결과 mybatis 설정을 해주기 때문이다.
복사된 java파일들
2. webContent 폴더
resources폴더, inc폴더, err, views 폴더를 그대로 복사하면 된다.
lib 폴더는 복사하지않는다.(maven이 알아서해준다.)
복사된 파일들.
study3_1의 webContent에서 복사한 파일들은 2번에 붙여넣기하면된다.
이 때 1번의 resources는 프로젝트 설정 Deployment Assembly에서
설정한 폴더로서 이름이 변경되면 안된다.
프로젝트 생성할 때 기본적으로 resources 폴더라는 이름으로 생성되는 폴더다.
src/main/resources 폴더와 같다.
2번의 resources폴더는 내 맘대로 지은거다. 이름이 bootjs든, bj 든 상관없다.
다만 2번 resources폴더이름을 바꾸면 mvc-servlet.xml의 <resources> 태그도 변경해줘야한다.
-----------------------------------------------------------------------------------------------------------------------------------
파일들을 복사했으면 이제 spring 답게 코드를 고치기만 하면 된다 .
기존 프로젝트에서도 모든내용을 JSP에서 하기만 하면 JSP코드가 길어져서 영역을 분리한다고 했다.
study3_1에서는 Service, Dao객체를 직접 생성(mybatis 코드로 생성했었다.) 했지만,
Spring 프로젝트에서는 관련 객체의 빈을 생성하고 주입해야 된다.
우리는 scan방식을 사용할 거기 때문에
각 클래스에 @Service(무슨무슨ServiceImpl), @Mapper(I무슨무슨Dao에 붙여준다)를 적용하면 된다.
기존의 FreeDelete, FreeEdit 등의 파일안에 있던 코드는 @Controller 객체의 1개의 메소드안에 작성한다.
개발순서는 따로 정해지지않았지만 여기서는 DAO, Service, Controller 순서로 보자.
DAO
우리가 DAO단에 관련있는건 IFreeBoardDAO같은 인터페이스와 거기에 관련된 mapper파일이다.
context-datasource에서 이 인터페이스의 구현체(Spring이 mybatis를 이용해서 만든다)를
빈으로 등록하기 위해서
<mybatis-spring:scan base-package="com.study"
annotation="org.apache.ibatis.annotations.Mapper" />
위와 같이 처럼 @Mapper 어노테이션을 스캔해서 빈으로 만들어준다고 한다.
우리는 IFreeBoardDAO 같은 인터페이스에 @Mapper만 붙이면된다.
ICommCodeDao.java
package com.study.code.dao;
import java.sql.Connection;
import java.util.List;
import org.apache.ibatis.annotations.Mapper;
import com.study.code.vo.CodeVO;
import com.study.exception.DaoException;
@Mapper
public interface ICommCodeDao {
public List<CodeVO> getCodeListByParent(String parentCode);
}
IFreeBoardDao.java
package com.study.free.dao;
import java.sql.Connection;
import java.util.List;
import java.util.Map;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import com.study.free.vo.FreeBoardSearchVO;
import com.study.free.vo.FreeBoardVO;
@Mapper
public interface IFreeBoardDao {
public int getTotalRowCount(FreeBoardSearchVO searchVO);
public List<FreeBoardVO> getBoardList(FreeBoardSearchVO searchVO);
public FreeBoardVO getBoard(int boNo);
public int increaseHit(int boNo);
public int updateBoard(FreeBoardVO board);
public int deleteBoard(FreeBoardVO board);
public int insertBoard(FreeBoardVO board);
}
나머지 Dao의 interface에도 @Mapper를 붙여주면 된다.
이 @Mapper를 붙이면 Spring이 알아서 우리가 만든 mapper파일(freeBoard.xml 등)과 연결시켜준다.
Service
spring이 아닌 mybatis만 사용할 때는 SqlSessionfactory객체로 부터 SqlSession객체를 얻고
SqlSession 객체로부터 mapper 객체를 얻었었다.
Spring에서는 SqlSessionfactory,SqlSession 부분이
이미 context-datasource.xml에서 빈으로 등록 되어있다.
우리는 mapper 객체만 어떤 mapper를 사용할지 정의 해주면 된다.
이 때 , Service는 Dao에 의존한다고 할 수 있다.
예시로 FreeBoardService는 IFreeBoardDao(의 구현체)에 의존한다.
즉, 우리는 @Service를 붙이고, I**Dao를 @Inject해주면 된다.
study3_1에서의 mapper얻는 코드는 삭제한다.
mybatis에서 제안하는대로 mapper 객체를 생성했지만,
Spring에서는 @Inject를 통해 Spring이 mapper객체를 생성한다.
CommCodeServiceImpl.java
@Service
public class CommCodeServiceImpl implements ICommCodeService{
@Inject
ICommCodeDao codeDao;
@Override
public List<CodeVO> getCodeListByParent(String parentCode) {
return codeDao.getCodeListByParent(parentCode);
}
}
FreeBoardServiceImpl.java
@Service
public class FreeBoardServiceImpl implements IFreeBoardService {
@Inject
IFreeBoardDao freeBoardDao;
@Override
public List<FreeBoardVO> getBoardList(FreeBoardSearchVO searchVO) {
int totalRowCount = freeBoardDao.getTotalRowCount(searchVO);
searchVO.setTotalRowCount(totalRowCount);
searchVO.pageSetting();
return freeBoardDao.getBoardList(searchVO);
}
// 나머지 메소드들도 try 부분 지우면 된다.
}
@Service를 붙일 때는 구현클래스에 붙인다. Interface에 붙이지 않도록 주의한다.
빈은 객체이다. Interface가 아닌 객체를 만들 수 있는 구현클래스에다 붙여야 한다.
@Mapper를 Interface에 붙이는건 spring과 mybatis가 mapper라는 구현 객체를 만들기 때문이다.
Controller
먼저 다음과 같이 FreeController를 만들자. 패키지는 com.study.free.web이다.
package com.study.free.web;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class FreeBoardController {
@RequestMapping("/free/freeList.wow")
public String freeList() {
return "free/freeList";
}
}
이 상태에서 프로젝트를 서버에 올리고 서버를 켜보자
(contextPath 확인하자. 아마 study4로 되어있을거다)
서버가 문제없이 켜지고localhost:8080/study4/free/freeList.wow를 요청해서
에러없이 화면이 나오면 설정은 잘 되어있다고 보면된다.
주의할 점은 반드시 @Controller를 붙여야한다.
그래야 DispatcherServlet이 우리가 만든 FreeBoardController를 실행한다.
Controller는 Service에 의존한다. 예시로 FreeBoardController는 FreeBoardService에 의존한다.
즉, FreeBoardService 객체를 의존주입해줘야한다.
@Inject를 이용해 @Service객체를 주입하면 된다.
@Service와 @Dao는 단순히 @Controller에서 실행되는 단순한 의존관계일 뿐이지만
@Controller,@Service,@DAO는 전부개발자가 실행흐름을 주도하고,
전부 개발자가 만든 코드들이다. @Controller에서 @Service 호출하고,
@Service에서 @DAO 호출할 뿐이다.
하지만 @Controller는 DispatcherServlet으로부터 실행을 위임받았다.
즉, @Controller가 원활히 실행되기 위해선
Spring프레임워크를 만드신 분들이 하라는 대로 작성해야된다.
Controller에서 사용하는 Model 객체
Controller의 메소드 중에서 파라미터에 다음과 같이 Model을 사용할 수 있다.
@Controller
public class FreeBoardController {
@RequestMapping(value="/free/freeList.wow" )
public String freeList(Model model) {
model.addAttribute("data", "내가 넣을려 하는 데이터,Object 아무거나가능");
return "free/freeList";
}
}
Spring 동작원리 6번에서
DispatcherServlet은 Controller -> HandlerAdapter로부터 ModelAndView를 받는다.
이 ModelAndView에서 View는 우리가 이동할 페이지다.
freeList의 메소드 return Type이 String일 경우 return 값을 가지고 view를 정한다.
Model은 이동할 페이지에 전달할 데이터를 담는다. 위에처럼 작성했을 시
/WEB-INF/views/free/freeList.jsp 로 포워딩하고 freeList.jsp에서 EL로 ${data}를 사용할 수 있다.
우리는 Controller를 작성한다.
Controller를 작성하면서 View이름과, View에서 사용할 데이터에 대한 내용을 작성한다.
이렇게 Controller에서 작성한 View이름 , 데이터를 어떠한 형태로든 HandlerAdapter로 넘긴다.
이 때 View이름과 데이터를 넘기는 방법은 많다.
위에서는 Model에 데이터를 담고, View이름은 return "free/freeList"로 넘겼지만
직접 ModelAndView를 이용해서 할 수도 있고, ModelMap, @ModelAttribute을 사용할 수도 있다.
우리가 어떤 방법을 쓰든 우리가 만든 Controller와 DispatcherServlet 사이에있는
HandlerAdapter과 Controller부터 전달받은 View의 이름과 View에서
사용할 데이터를 ModelAndView형태로 만들어서 DispatcherServlet에 전달한다.
Controller에서 사용하는 @어노테이션
@Controller | 해당 클래스가 Controller임을 나타내기 위한 어노테이션 |
@RequestMapping |
요청에 대핸 어떤 Controller, 어떤 메소드가 처리할지를 매핑하기 위한 어노테이션 |
@RequestParam | Controller 메소드의 파라미터와 웹 요청 파라미터를 매핑하기 위한 어노테이션 |
@ModelAttribute | Controller 메소드의 파라미터나 리턴값을 Model 객체와 바인딩하기 위한 어노테이션 |
@SessionAttributes | Model 객체를 세션에 저장하고 사용하기 위한 어노테이션 |
1. @Controller
어떤 클래스에 @Controller를 붙이면 Spring(정확히는 DispatcherServlet)이 빈을 만들어
요청이 올 때 DispacherServlet 전체과정 중 Controller로서 사용한다.
2.RequestMapping
관련속성
이름 | 타입 | 매핑 조건 | 설명 |
value | String[] | URL 값 | -@RequestMapping (value="/hello.do") -@RequestMapping(value={"/hello.do","/free/freeeList.wow"} -@RequestMapping("hello.do") |
method | ReuqestMethod[] | HTTPRequest 메소드 값 |
-@RequestMapping(method=RequestMethod.POST) -사용가능한 메소드 : GET,POST,HEAD,OPTIONS,PUT,DELETE,TRACE |
params | String[] | HTTPRequest 파라미터 |
- params=“myParam=myValue” =>HTTP Request URL중에 myParam이라는 파 라미터가 있어야 하고 값은 myValue이어야 맵핑 - params=“myParam” =>파라미터 이름만으로 조건을 부여 - ”!myParam” =>myParam이라는 파라미터가 없는 요청 만을 맵핑 - @RequestMapping(params={“myParam1=myValue”,“myParam2”, ”!myParam3”}) =>HTTP Request에는 파라미터 myParam1이 myValue값을 가지고 있고, myParam2 파라미터가 있어야 하고, myParam3라는 파라미터는 없어야함. |
2_1.@GetMapping
@RequestMapping( method=RequestMethod.GET) 이랑 같다.
2_2@PostMapping
@RequestMapping( method=RequestMethod.POST) 이랑 같다.
3.@RequestParam
관련 속성
이름 | 타입 | 설명 |
value | String | 파라미터 이름 |
required | boolean | 해당 파라미터의 필수 여부.기본값은 true이다 |
@RequestMapping("/hello.do")
public String hello( @RequestParam(value="memId", required=false)String memId){
}
4. @ModelAttribute
@ModelAttribute는 2가지 방식으로 쓰인다.
첫번째, 메소드의 파라미터에 쓰일 떄 : 요청 파라미터의 이름이 바인딩 객체의 필드와 같을 경우 자동 매핑
이름 | 타입 | 설명 |
value | String | 바인드하려는 Model 속성 이름 |
@RequestMapping("/hello.do")
public String hello(@ModelAttribute(value="member") MemberVO member){
}
@RequestMapping("/hello.do")
public String hello(@ModelAttribute("member")MemberVO member){
}
memberVO의 필드에 memId가 있고, 요청 파라미터가 memId=창희 인 경우
자동으로 member의 memId 값은 "창희"가 된다.
두번째, 메소드에 쓰일 때 :
모든 @RequestMapping의 메소드가 시작되기 전에 Model에 리턴값을 담는다.
@ModelAttribute("cateList")
public List<CodeVO> cateList(){
return codeService.getCodeListByParent("BC00");
}
Model에 List<CodeVO> 타입의 return 값을 "cateList" 라는 이름으로 담는다.
5.@SessionAttributes
@SessionAttributes는 model attribute를 session에 저장, 유지할 때 사용하는 어노테이션이다
이 때 session 전체영역이 아닌 @Controller 내에서만 model attribute가 유지된다.
이름 | 타입 | 설명 |
value | String[] | session에 저장하려는 model attribute의 이름 |
required | Class | session에 저장하려는 model attribute 타입 |
Controller 작성
먼저 Controller단에서는 Service에 의존한다.
즉 Service를 필드,생성자,세터 방식중 하나로 Inject해줘야한다.
여기서는 필드방식으로 Inject해줄것이다. FreeBoardController필요한 Service들을 주입하자.
@Controller
public class FreeBoardController {
@Inject
IFreeBoardService freeBoardService ;
@Inject
ICommCodeService codeService;
}
study3_1에서는 MVC Command 패턴을 적용해 URL요청 하나당 freeList.java, freeEdit.java 등을 만들었다.
spring에서는 URL요청 하나당 @RequestMapping 이 붙은 메소드한개씩 만들면 된다.
study3_1의 FreeList.java
public class FreeList implements Handler{
@Override
public String process(HttpServletRequest req, HttpServletResponse resp) throws Exception {
// request로 넘어온 파라미터들 searchVO에 한번에 세팅
FreeBoardSearchVO searchVO = new FreeBoardSearchVO();
BeanUtils.populate(searchVO, req.getParameterMap());
req.setAttribute("searchVO", searchVO);
IFreeBoardService freeBoardService = new FreeBoardServiceImpl();
List<FreeBoardVO> freeBoardList = freeBoardService.getBoardList(searchVO);
req.setAttribute("freeBoardList", freeBoardList);
ICommCodeService codeService = new CommCodeServiceImpl();
List<CodeVO> cateList = codeService.getCodeListByParent("BC00");
req.setAttribute("cateList", cateList);
return "free/freeList";
}
}
를 다음과 같이 적용하면 된다.
@RequestMapping("/free/freeList.wow") freeList
@RequestMapping(value="/free/freeList.wow" )
public String freeList(Model model,@ModelAttribute("searchVO")FreeBoardSearchVO searchVO
//searchVO의 필드이름이랑 요청파라미터이름이 같으면 그 값을 자등올 setting한 다음 model에 "searchVO"라는 이름으로 담는다
// Beanutils.populate() 가 해주는 일은 메소드 파라미터에 VO를 명시해주기만 하면 된다.
) {
List<FreeBoardVO> freeBoardList = freeBoardService.getBoardList(searchVO); //객체를 생성하지않아도 주입받아서 사용한다
model.addAttribute("freeBoardList", freeBoardList); //request 객체에 데이터를 담는대신 model 담는다.
List<CodeVO> cateList = codeService.getCodeListByParent("BC00");//객체를 생성하지않아도 주입받아서 사용한다
model.addAttribute("cateList", cateList); //request 객체에 데이터를 담는대신 model 담는다.
return "free/freeList"; //DispatcherServlet이 ViewResolver를 이용해서 /WEB-INF/views/free/freeList.jsp 로 forward한다.
}
마찬가지로 나머지 메소드들도 적용해주면 된다.
@RequestMapping("/free/freeView.wow") freeView
@RequestMapping("/free/freeView.wow")
public String freeView(Model model, @RequestParam(required = true) int boNo) {
//파라미터로 boNo가 반드시 있어야함을 명시. 없으면 에러남 @RequestParam안 붙여도 기본적으로 required=true
try {
FreeBoardVO freeBoard = freeBoardService.getBoard(boNo);
model.addAttribute("freeBoard", freeBoard);
freeBoardService.increaseHit(boNo);
} catch (BizNotFoundException enf) {
ResultMessageVO resultMessageVO = new ResultMessageVO();
resultMessageVO.messageSetting(false, "글 찾기 실패", "글을 찾는데 실패했습니다. 해당 글이없습니다.", "/free/freeList.wow", "목록으로");
model.addAttribute("resultMessageVO", resultMessageVO);
return "common/message";
} catch (BizNotEffectedException ene) {
ResultMessageVO resultMessageVO = new ResultMessageVO();
resultMessageVO.messageSetting(false, "조회수증가실패", "조회수증가실패했습니다.", "/free/freeList.wow", "목록으로");
model.addAttribute("resultMessageVO", resultMessageVO);
return "common/message"; // 비정상적 실행에는 /WEB-INF/views/common/message.jsp로
}
return "free/freeView"; //정상적 실행에는 /WEB-INF/views/free/freeView.jsp로 forward
}
@RequestMapping("/free/freeEdit.wow") freeEdit
@RequestMapping(value = "/free/freeEdit.wow", params = { "boNo" })
public String freeEdit(Model model, int boNo) {
try {
FreeBoardVO freeBoard = freeBoardService.getBoard(boNo);
model.addAttribute("freeBoard", freeBoard);
} catch (BizNotFoundException enf) {
ResultMessageVO resultMessageVO = new ResultMessageVO();
resultMessageVO.messageSetting(false, "글 찾기 실패", "글을 찾는데 실패했습니다. 해당 글이없습니다.", "/free/freeList.wow", "목록으로");
model.addAttribute("resultMessageVO", resultMessageVO);
return "common/message";
}
List<CodeVO> cateList=codeService.getCodeListByParent("BC00");
model.addAttribute("cateList", cateList);
return "free/freeEdit";
}
@RequestMapping("/free/freeModify") freeModify
@PostMapping("/free/freeModify.wow")
// @RequestMapping(value = "/free/freeModify.wow" , method = RequestMethod.POST), Post방식만 허용
public String freeModify(Model model,@ModelAttribute("freeBoard") FreeBoardVO freeBoard) {
try {
freeBoardService.modifyBoard(freeBoard);
ResultMessageVO resultMessageVO = new ResultMessageVO();
resultMessageVO.messageSetting(true, "글 수정 성공", "글을 수정했습니다.", "/free/freeList.wow", "목록으로");
model.addAttribute("resultMessageVO", resultMessageVO);
return "common/message";
} catch (BizNotFoundException enf) {
// 에러가 났을 때 freeView에 있는 너무 간단한 화면말고 message.jsp로 이동하자
ResultMessageVO resultMessageVO = new ResultMessageVO();
resultMessageVO.messageSetting(false, "글 찾기 실패", "글을 찾는데 실패했습니다. 해당 글이없습니다.", "/free/freeList.wow", "목록으로");
model.addAttribute("resultMessageVO", resultMessageVO);
return "common/message";
} catch (BizPasswordNotMatchedException epm) {
ResultMessageVO resultMessageVO = new ResultMessageVO();
resultMessageVO.messageSetting(false, "글 수정 실패 ", "글을 수정하는데 실패했습니다. 비밀번호가 달라요", "/free/freeList.wow",
"목록으로");
model.addAttribute("resultMessageVO", resultMessageVO);
return "common/message";
} catch (BizNotEffectedException ene) {
ResultMessageVO resultMessageVO = new ResultMessageVO();
resultMessageVO.messageSetting(false, "수정실패", "수정에 실패했습니다.", "/free/freeList.wow", "목록으로");
model.addAttribute("resultMessageVO", resultMessageVO);
return "common/message";
}
}
@RequestMapping("/free/freeDelete") freeDelete
@PostMapping("/free/freeDelete.wow")
public String freeDelete(Model model, @ModelAttribute("freeBoard")FreeBoardVO freeBoard) {
try {
freeBoardService.removeBoard(freeBoard);
// message.jsp로 가도록
ResultMessageVO resultMessageVO = new ResultMessageVO();
resultMessageVO.messageSetting(true, "글 삭제 성공", "글을 삭제했습니다.", "/free/freeList.wow", "목록으로");
model.addAttribute("resultMessageVO", resultMessageVO);
return "common/message";
} catch (BizNotFoundException enf) {
ResultMessageVO resultMessageVO = new ResultMessageVO();
resultMessageVO.messageSetting(false, "글 찾기 실패", "글을 찾는데 실패했습니다. 해당 글이없습니다.", "/free/freeList.wow", "목록으로");
model.addAttribute("resultMessageVO", resultMessageVO);
return "common/message";
} catch (BizPasswordNotMatchedException epm) {
ResultMessageVO resultMessageVO = new ResultMessageVO();
resultMessageVO.messageSetting(false, "글 수정 실패 ", "글을 수정하는데 실패했습니다. 비밀번호가 달라요", "/free/freeList.wow","목록으로");
model.addAttribute("resultMessageVO", resultMessageVO);
return "common/message";
} catch (BizNotEffectedException ene) {
ResultMessageVO resultMessageVO = new ResultMessageVO();
resultMessageVO.messageSetting(false, "조회수증가실패", "조회수증가실패했습니다.", "/free/freeList.wow", "목록으로");
model.addAttribute("resultMessageVO", resultMessageVO);
return "common/message";
}
}
@RequestMapping("/free/freeForm") freeForm
@GetMapping("/free/freeForm.wow")
public String freeForm(Model model) {
List<CodeVO> cateList=codeService.getCodeListByParent("BC00");
model.addAttribute("cateList", cateList);
return "free/freeForm";
}
@RequestMapping("/free/freeRegist") freeRegist
@PostMapping("/free/freeRegist.wow")
public String freeRegist(Model model, @ModelAttribute("freeBoard")FreeBoardVO freeBoard) {
try {
freeBoardService.registBoard(freeBoard);
ResultMessageVO resultMessageVO = new ResultMessageVO();
resultMessageVO.messageSetting(true, "글 등록 성공", "글을 등록했습니다.", "/free/freeList.wow", "목록으로");
model.addAttribute("resultMessageVO", resultMessageVO);
return "common/message";
} catch (BizNotEffectedException ebe) {
ResultMessageVO resultMessageVO = new ResultMessageVO();
resultMessageVO.messageSetting(false, "등록실패", "등록에 실패했습니다.", "/free/freeList.wow", "목록으로");
model.addAttribute("resultMessageVO", resultMessageVO);
return "common/message";
}
}
이렇게 Controller단에 URL요청을 처리하는 메소드를 만들어주었다면
기존의 있던 freeList.java 등은 삭제해주자.
여기서 한가지 더. freeList, freeEdit, freeForm을 보면 공통적으로
codeService.getCodeListByParent("BC00")을 model에 "cateList"라는 이름으로 담고 있다.
이렇게 어떤 요청마다 공통적으로 model에 담는 데이터가 있을 시
@ModeAttribute 메소드를 이용해서 코드 중복을 해결 할 수 있다.
@ModelAttribute("cateList") //model에 담길 이름
public List<CodeVO> cateList(){
return codeService.getCodeListByParent("BC00"); //return값이 model에 담길 값
}
이 메소드를 만들면 freeList,freeEdit,freeForm에서
List<CodeVO> cateList=codeService.getCodeListByParent("BC00");
model.addAttribute("cateList", cateList);
부븐은 필요없게된다. @ModelAttribute를 통해 이미 데이터가 담기기 때문이다.
(실제로 @ModelAttribue메소드를 통해 model에 데이터를 먼저 담고 @RequestMapping 메소드를 실행한다)
완성된 FreeBoardController.java
package com.study.free.web;
import java.util.List;
import javax.inject.Inject;
import org.apache.commons.beanutils.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
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.servlet.ModelAndView;
import com.study.code.service.CommCodeServiceImpl;
import com.study.code.service.ICommCodeService;
import com.study.code.vo.CodeVO;
import com.study.common.vo.ResultMessageVO;
import com.study.exception.BizNotEffectedException;
import com.study.exception.BizNotFoundException;
import com.study.exception.BizPasswordNotMatchedException;
import com.study.free.service.FreeBoardServiceImpl;
import com.study.free.service.IFreeBoardService;
import com.study.free.vo.FreeBoardSearchVO;
import com.study.free.vo.FreeBoardVO;
@Controller
public class FreeBoardController {
@Inject
IFreeBoardService freeBoardService;
@Autowired
ICommCodeService codeService;
@ModelAttribute("cateList")
public List<CodeVO> cateList(){
return codeService.getCodeListByParent("BC00");
}
@RequestMapping("/free/freeList.wow")
public String freeList(Model model, @ModelAttribute("searchVO") FreeBoardSearchVO searchVO) {
// 파라미터들이 searchVO의 필드이면 알아서 다세팅 + model.addAttribute("searchVO")
List<FreeBoardVO> freeBoardList = freeBoardService.getBoardList(searchVO);
model.addAttribute("freeBoardList", freeBoardList);
return "free/freeList";
}
@RequestMapping("/free/freeView.wow")
public String freeView(Model model, @RequestParam(required = true) int boNo) {
try {
FreeBoardVO freeBoard = freeBoardService.getBoard(boNo);
model.addAttribute("freeBoard", freeBoard);
freeBoardService.increaseHit(boNo);
} catch (BizNotFoundException enf) {
ResultMessageVO resultMessageVO = new ResultMessageVO();
resultMessageVO.messageSetting(false, "글 찾기 실패", "글을 찾는데 실패했습니다. 해당 글이없습니다.", "/free/freeList.wow", "목록으로");
model.addAttribute("resultMessageVO", resultMessageVO);
return "common/message";
} catch (BizNotEffectedException ene) {
ResultMessageVO resultMessageVO = new ResultMessageVO();
resultMessageVO.messageSetting(false, "조회수증가실패", "조회수증가실패했습니다.", "/free/freeList.wow", "목록으로");
model.addAttribute("resultMessageVO", resultMessageVO);
return "common/message";
}
return "free/freeView";
}
@RequestMapping(value = "/free/freeEdit.wow", params = { "boNo" })
public String freeEdit(Model model, int boNo) {
try {
FreeBoardVO freeBoard = freeBoardService.getBoard(boNo);
model.addAttribute("freeBoard", freeBoard);
} catch (BizNotFoundException enf) {
ResultMessageVO resultMessageVO = new ResultMessageVO();
resultMessageVO.messageSetting(false, "글 찾기 실패", "글을 찾는데 실패했습니다. 해당 글이없습니다.", "/free/freeList.wow", "목록으로");
model.addAttribute("resultMessageVO", resultMessageVO);
return "common/message";
}
return "free/freeEdit";
}
@PostMapping("/free/freeModify.wow")
public String freeModify(Model model, @ModelAttribute("freeBoard")FreeBoardVO freeBoard) {
try {
freeBoardService.modifyBoard(freeBoard);
ResultMessageVO resultMessageVO = new ResultMessageVO();
resultMessageVO.messageSetting(true, "글 수정 성공", "글을 수정했습니다.", "/free/freeList.wow", "목록으로");
model.addAttribute("resultMessageVO", resultMessageVO);
return "common/message";
} catch (BizNotFoundException enf) {
// 에러가 났을 때 freeView에 있는 너무 간단한 화면말고 message.jsp로 이동하자
ResultMessageVO resultMessageVO = new ResultMessageVO();
resultMessageVO.messageSetting(false, "글 찾기 실패", "글을 찾는데 실패했습니다. 해당 글이없습니다.", "/free/freeList.wow", "목록으로");
model.addAttribute("resultMessageVO", resultMessageVO);
return "common/message";
} catch (BizPasswordNotMatchedException epm) {
ResultMessageVO resultMessageVO = new ResultMessageVO();
resultMessageVO.messageSetting(false, "글 수정 실패 ", "글을 수정하는데 실패했습니다. 비밀번호가 달라요", "/free/freeList.wow",
"목록으로");
model.addAttribute("resultMessageVO", resultMessageVO);
return "common/message";
} catch (BizNotEffectedException ene) {
ResultMessageVO resultMessageVO = new ResultMessageVO();
resultMessageVO.messageSetting(false, "수정실패", "수정에 실패했습니다.", "/free/freeList.wow", "목록으로");
model.addAttribute("resultMessageVO", resultMessageVO);
return "common/message";
}
}
@PostMapping("/free/freeDelete.wow")
public String freeDelete(Model model, @ModelAttribute("freeBoard") FreeBoardVO freeBoard) {
try {
freeBoardService.removeBoard(freeBoard);
// message.jsp로 가도록
ResultMessageVO resultMessageVO = new ResultMessageVO();
resultMessageVO.messageSetting(true, "글 삭제 성공", "글을 삭제했습니다.", "/free/freeList.wow", "목록으로");
model.addAttribute("resultMessageVO", resultMessageVO);
return "common/message";
} catch (BizNotFoundException enf) {
// 에러가 났을 때 freeView에 있는 너무 간단한 화면말고 message.jsp로 이동하자
ResultMessageVO resultMessageVO = new ResultMessageVO();
resultMessageVO.messageSetting(false, "글 찾기 실패", "글을 찾는데 실패했습니다. 해당 글이없습니다.", "/free/freeList.wow", "목록으로");
model.addAttribute("resultMessageVO", resultMessageVO);
return "common/message";
} catch (BizPasswordNotMatchedException epm) {
ResultMessageVO resultMessageVO = new ResultMessageVO();
resultMessageVO.messageSetting(false, "글 수정 실패 ", "글을 수정하는데 실패했습니다. 비밀번호가 달라요", "/free/freeList.wow",
"목록으로");
model.addAttribute("resultMessageVO", resultMessageVO);
return "common/message";
} catch (BizNotEffectedException ene) {
ResultMessageVO resultMessageVO = new ResultMessageVO();
resultMessageVO.messageSetting(false, "조회수증가실패", "조회수증가실패했습니다.", "/free/freeList.wow", "목록으로");
model.addAttribute("resultMessageVO", resultMessageVO);
return "common/message";
}
}
@GetMapping("/free/freeForm.wow")
public String freeForm(Model model) {
return "free/freeForm";
}
@PostMapping("/free/freeRegist.wow")
public String freeRegist(Model model, @ModelAttribute("freeBoard")FreeBoardVO freeBoard) {
try {
freeBoardService.registBoard(freeBoard);
ResultMessageVO resultMessageVO = new ResultMessageVO();
resultMessageVO.messageSetting(true, "글 등록 성공", "글을 등록했습니다.", "/free/freeList.wow", "목록으로");
model.addAttribute("resultMessageVO", resultMessageVO);
return "common/message";
} catch (BizNotEffectedException ebe) {
ResultMessageVO resultMessageVO = new ResultMessageVO();
resultMessageVO.messageSetting(false, "등록실패", "등록에 실패했습니다.", "/free/freeList.wow", "목록으로");
model.addAttribute("resultMessageVO", resultMessageVO);
return "common/message";
}
}
}
나머지 member,login,mypage에도 Controller,Service,Dao를 Spring처럼 적용해보자.
Service,Dao부분은 어려울게 없으니 여기서는 Controller단만 작성하겠다.
MemberController.java
package com.study.member.web;
import java.util.List;
import javax.inject.Inject;
import org.apache.commons.beanutils.BeanUtils;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import com.study.code.service.CommCodeServiceImpl;
import com.study.code.service.ICommCodeService;
import com.study.code.vo.CodeVO;
import com.study.common.vo.ResultMessageVO;
import com.study.exception.BizDuplicateKeyException;
import com.study.exception.BizNotEffectedException;
import com.study.exception.BizNotFoundException;
import com.study.member.service.IMemberService;
import com.study.member.service.MemberServiceImpl;
import com.study.member.vo.MemberSearchVO;
import com.study.member.vo.MemberVO;
@Controller
public class MemberController {
@Inject
IMemberService memberService;
@Inject
ICommCodeService codeService;
@ModelAttribute("jobList")
public List<CodeVO> jobList() {
return codeService.getCodeListByParent("JB00");
}
@ModelAttribute("hobbyList")
public List<CodeVO> hobbyList() {
return codeService.getCodeListByParent("HB00");
}
@RequestMapping("/member/memberList.wow")
public String memberList(Model model, @ModelAttribute("searchVO") MemberSearchVO searchVO) {
List<MemberVO> memberList = memberService.getMemberList(searchVO);
model.addAttribute("memberList", memberList);
return "member/memberList";
}
@RequestMapping("/member/memberView.wow")
public String memberView(Model model, @RequestParam(value = "memId",required = true) String memId) {
try {
MemberVO member = memberService.getMember(memId);
model.addAttribute("member", member);
} catch (BizNotFoundException enf) {
// 에러가 났을 때 freeView에 있는 너무 간단한 화면말고 message.jsp로 이동하자
ResultMessageVO resultMessageVO = new ResultMessageVO();
resultMessageVO.messageSetting(false, "회원 찾기 실패", "회원을 찾는데 실패했습니다.", "/member/memberList.wow", "목록으로");
model.addAttribute("resultMessageVO", resultMessageVO);
return "common/message";
}
return "member/memberView";
}
@RequestMapping("/member/memberEdit.wow")
public String memberEdit(Model model, @RequestParam(value = "memId",required = true) String memId) {
try {
MemberVO member = memberService.getMember(memId);
model.addAttribute("member", member);
} catch (BizNotFoundException enf) {
// 에러가 났을 때 freeView에 있는 너무 간단한 화면말고 message.jsp로 이동하자
ResultMessageVO resultMessageVO = new ResultMessageVO();
resultMessageVO.messageSetting(false, "회원 찾기 실패", "회원을 찾는데 실패했습니다.", "/member/memberList.wow", "목록으로");
model.addAttribute("resultMessageVO", resultMessageVO);
return "common/message";
}
return "member/memberEdit";
}
@RequestMapping(value = "/member/memberModify.wow", method = RequestMethod.POST)
public String memberModify(Model model, @ModelAttribute("member") MemberVO member) {
try {
memberService.modifyMember(member);
ResultMessageVO resultMessageVO = new ResultMessageVO();
resultMessageVO.messageSetting(true, "회원 수정 성공 ", "회원정보를 수정했습니다.", "/member/memberList.wow", "목록으로");
model.addAttribute("resultMessageVO", resultMessageVO);
return "common/message";
} catch (BizNotEffectedException ene) {
ResultMessageVO resultMessageVO = new ResultMessageVO();
resultMessageVO.messageSetting(false, "회원 삭제 실패", "회원을 삭제하는데 실패했습니다.", "/member/memberList.wow", "목록으로");
model.addAttribute("resultMessageVO", resultMessageVO);
return "common/message";
} catch (BizNotFoundException enf) {
// 에러가 났을 때 freeView에 있는 너무 간단한 화면말고 message.jsp로 이동하자
ResultMessageVO resultMessageVO = new ResultMessageVO();
resultMessageVO.messageSetting(false, "회원 찾기 실패", "회원을 찾는데 실패했습니다.", "/member/memberList.wow", "목록으로");
model.addAttribute("resultMessageVO", resultMessageVO);
return "common/message";
}
}
@PostMapping("/member/memberDelete.wow")
public String memberDelete(Model model, @ModelAttribute("member") MemberVO member) {
try {
memberService.removeMember(member);
ResultMessageVO resultMessageVO = new ResultMessageVO();
resultMessageVO.messageSetting(true, "회원 삭제 성공 ", "회원 삭제했습니다.", "/member/memberList.wow", "목록으로");
model.addAttribute("resultMessageVO", resultMessageVO);
return "common/message";
} catch (BizNotEffectedException ene) {
ResultMessageVO resultMessageVO = new ResultMessageVO();
resultMessageVO.messageSetting(false, "회원 삭제 실패", "회원을 삭제하는데 실패했습니다.", "/member/memberList.wow", "목록으로");
model.addAttribute("resultMessageVO", resultMessageVO);
return "common/message";
} catch (BizNotFoundException enf) {
// 에러가 났을 때 freeView에 있는 너무 간단한 화면말고 message.jsp로 이동하자
ResultMessageVO resultMessageVO = new ResultMessageVO();
resultMessageVO.messageSetting(false, "회원 찾기 실패", "회원을 찾는데 실패했습니다.", "/member/memberList.wow", "목록으로");
model.addAttribute("resultMessageVO", resultMessageVO);
return "common/message";
}
}
@GetMapping("/member/memberForm.wow")
public String memberForm() {
return "member/memberForm";
}
@PostMapping("/member/memberRegist.wow")
public String memberRegist(Model model, @ModelAttribute("member") MemberVO member) {
try {
memberService.registMember(member);
ResultMessageVO resultMessageVO = new ResultMessageVO();
resultMessageVO.messageSetting(true, "회원 등록 성공 ", "회원을 등록했습니다.", "/member/memberList.wow", "목록으로");
model.addAttribute("resultMessageVO", resultMessageVO);
return "common/message";
} catch (BizNotEffectedException ene) {
ResultMessageVO resultMessageVO = new ResultMessageVO();
resultMessageVO.messageSetting(false, "회원 삭제 실패", "회원을 삭제하는데 실패했습니다.", "/member/memberList.wow", "목록으로");
model.addAttribute("resultMessageVO", resultMessageVO);
return "common/message";
} catch (BizDuplicateKeyException ede) {
ResultMessageVO resultMessageVO = new ResultMessageVO();
resultMessageVO.messageSetting(false, "회원 등록 실패", "회원아이디가 이미 존재합니다.", "/member/memberList.wow", "목록으로");
model.addAttribute("resultMessageVO", resultMessageVO);
return "common/message";
}
}
}
LoginController.java
package com.study.login.web;
import java.net.URLEncoder;
import javax.inject.Inject;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.springframework.http.HttpRequest;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import com.study.common.util.CookieUtils;
import com.study.login.service.ILoginService;
import com.study.login.service.LoginServiceImpl;
import com.study.login.vo.UserVO;
@Controller
public class LoginController {
@Inject
ILoginService loginService;
@GetMapping("/login/login.wow")
public String loginGet() {
return "login/login";
}
@PostMapping("/login/login.wow")
public String loginPost(HttpServletRequest req, HttpServletResponse resp) throws Exception {
// 사용자가 id,pass입력해서 로그인버튼 누름
String id = req.getParameter("userId");
String pw = req.getParameter("userPass");
String save_id = req.getParameter("rememberMe");
if (save_id == null) {
CookieUtils cookieUtils = new CookieUtils(req);
if (cookieUtils.exists("SAVE_ID")) {
Cookie cookie = CookieUtils.createCookie("SAVE_ID", id, "/", 0);
resp.addCookie(cookie);
}
save_id = "";
}
if ((id == null || id.isEmpty()) || (pw == null || pw.isEmpty())) {
return "redirect:" + "/login/login.wow?msg=" + URLEncoder.encode("입력안했어요", "utf-8");
// 직접 redirect보다는 DS한테 나 redirect하고싶어 를 알려주는게...
} else {
// DB에 있는 member테이블을 조회해서 로그인가능여부판단.
UserVO user = loginService.getUser(id);
if (user == null) {
return "redirect:" + "/login/login.wow?msg="
+ URLEncoder.encode("아이디 또는 비번확인", "utf-8");
} else { // id맞았을때
if (user.getUserPass().equals(pw)) {// 다 맞는경우
if (save_id.equals("Y")) {
resp.addCookie(CookieUtils.createCookie("SAVE_ID", id, "/", 3600 * 24 * 7));
}
HttpSession session = req.getSession();
session.setAttribute("USER_INFO", user);
return "redirect:" + "/";
// redirect:/study3
} else {// 비번만 틀린경우
return "redirect:" + "/login/login.wow?msg="
+ URLEncoder.encode("아이디 또는 비번확인", "utf-8");
}
}
}
}
@RequestMapping("/login/logout.wow")
public String logout( HttpSession session, HttpServletRequest req) {
session.removeAttribute("USER_INFO");
return "redirect:"+"/";
}
}
MypageController.java
package com.study.mypage.web;
import java.util.List;
import javax.inject.Inject;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import org.apache.commons.beanutils.BeanUtils;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import com.study.code.service.CommCodeServiceImpl;
import com.study.code.service.ICommCodeService;
import com.study.code.vo.CodeVO;
import com.study.common.vo.ResultMessageVO;
import com.study.exception.BizNotEffectedException;
import com.study.exception.BizNotFoundException;
import com.study.login.vo.UserVO;
import com.study.member.service.IMemberService;
import com.study.member.service.MemberServiceImpl;
import com.study.member.vo.MemberVO;
@Controller
public class MypageController {
@Inject
IMemberService memberService;
@Inject
ICommCodeService codeService;
@ModelAttribute("jobList")
public List<CodeVO> jobList() {
return codeService.getCodeListByParent("JB00");
}
@ModelAttribute("hobbyList")
public List<CodeVO> hobbyList() {
return codeService.getCodeListByParent("HB00");
}
@RequestMapping("/mypage/info.wow")
public String info(Model model, HttpSession session,HttpServletRequest req) {
UserVO user = (UserVO) session.getAttribute("USER_INFO");
//study3_1에서 filter를 적용했을 땐 필요없었지만, spring에서 login관련 filter체크를 안했기 때문에 필요 , 나중에 interceptor 적용하면 필요없는코드
if(user==null) {
return "redirect:"+req.getContextPath()+"/login/login.wow";
}
try {
MemberVO member = memberService.getMember(user.getUserId());
model.addAttribute("member", member);
return "mypage/info";
} catch (BizNotFoundException e) {
ResultMessageVO resultMessageVO = new ResultMessageVO();
resultMessageVO.messageSetting(false, "회원없음", "회원이없습니다", "/", "홈으로");
model.addAttribute("resultMessageVO", resultMessageVO);
return "common/message";
}
}
@RequestMapping("/mypage/edit.wow")
public String edit(Model model, HttpSession session,HttpServletRequest req) {
UserVO user = (UserVO) session.getAttribute("USER_INFO");
//study3_1에서 filter를 적용했을 땐 필요없었지만, spring에서 login관련 filter체크를 안했기 때문에 필요 , 나중에 interceptor 적용하면 필요없는코드
if(user==null) {
return "redirect:"+req.getContextPath()+"/login/login.wow";
}
try {
MemberVO member = memberService.getMember(user.getUserId());
model.addAttribute("member", member);
return "mypage/edit";
} catch (BizNotFoundException e) {
ResultMessageVO resultMessageVO = new ResultMessageVO();
resultMessageVO.messageSetting(false, "회원없음", "회원이없습니다", "/", "홈으로");
model.addAttribute("resultMessageVO", resultMessageVO);
return "common/message";
}
}
@RequestMapping("/mypage/modify.wow")
public String modify(Model model, HttpSession session, HttpServletRequest req,
@ModelAttribute("member") MemberVO member) {
UserVO user = (UserVO) session.getAttribute("USER_INFO");
//study3_1에서 filter를 적용했을 땐 필요없었지만, spring에서 login관련 filter체크를 안했기 때문에 필요 , 나중에 interceptor 적용하면 필요없는코드
if(user==null) {
return "redirect:"+req.getContextPath()+"/login/login.wow";
}
try {
memberService.modifyMember(member);
user.setUserName(member.getMemName());
user.setUserPass(member.getMemPass());
session.setAttribute("USER_INFO", user);
return "redirect:" + "/";
} catch (BizNotFoundException e) {
ResultMessageVO resultMessageVO = new ResultMessageVO();
resultMessageVO.messageSetting(false, "내정보없음", "내정보가 없습니다", "/", "홈으로");
model.addAttribute("resultMessageVO", resultMessageVO);
return "common/message";
} catch (BizNotEffectedException e) {
ResultMessageVO resultMessageVO = new ResultMessageVO();
resultMessageVO.messageSetting(false, "내정보수정실패", "내정보 수정실패했습니다", "/", "홈으로");
model.addAttribute("resultMessageVO", resultMessageVO);
return "common/message";
}
}
}
※사실 spring DI를 했다면 Spring은 끝났다고 봐도 무방하다.
여기서는 web사이트를 만드는 실습을 위해 Spring MVC에 대해 자세히 살펴보았다.
물론 이 외의 Spring에는 다양한 기능(모듈)이 많이 있을 것이다. 물론 그 기능들은
Spring에서 지원해주는 객체가 할 것이고, 그 객체를 관리하기 위해 빈을 등록할 것이다.
그 때마다 DI에 대한 개념만 가지고 있다면 다른 Spring 모듈은 쉽게 적용할 수 있을 것이다.