Spring framework 4.X
properties 파일 사용하여 JDBC
applicationContext.xml
<!-- JDBC -->
<bean
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"
p:location="classpath:info.properties"/>
<bean
id="dataSource"
class="org.springframework.jdbc.datasource.SimpleDriverDataSource"
p:driverClass="com.mysql.cj.jdbc.Driver"
p:url="${db.url}" p:username="${db.user}" p:password="${db.password}"/>
info.properties
db.url=jdbc:mysql://192.168.99.000:3306/lecture
db.user=scott
db.password=tiger
Junit
앞서 junit테스트를 사용할 때 어떤 xml을 읽어들일지에 대한 선택을 어노테이션으로 할 수 있다. 배열로 여러개 선택도 가능
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:/applicationContext.xml")
//@ContextConfiguration("file:src/main/webapp/WEB-INF/spring/root-context.xml")
//@ContextConfiguration({
// "classpath:/applicationContext.xml",
// "file:src/main/webapp/WEB-INF/spring/root-context.xml"
// })
public class ApplicationTest {
@Autowired
DataSource dataSource;
@Test
public void test() {
assertNotNull(dataSource);
}
}
mybatis
Spring version 3.X 최종버전 부터 안정적으로 사용가능하다 오류가 발생되었을 때 버전을 확인해보자!
mybatis-context.xml 파일 생성 후 스키마 복붙 및 기본 세팅
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<mappers>
<mapper resource="mapper/dept-mapper.xml"/>
</mappers>
</configuration>
mapper/dept-mapper.xml 만든 후 스키마 복붙 !위와 스키마가 다름
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper>
</mapper>
applicationContext.xml
<!-- Mybatis -->
<bean
id="sqlSessionFactory"
class="org.mybatis.spring.SqlSessionFactoryBean"
p:configLocation="classpath:/mybatis-config.xml"
p:dataSource-ref="dataSource"/>
<bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
<constructor-arg ref="sqlSessionFactory"></constructor-arg>
</bean>
DeptVO, DeptDao(interface) 까지만 정의 후 dept-mapper.xml 추가 작성
<mapper namespace="com.bit.sts07.model.DeptDao">
<select id="findAll" resultType="com.bit.sts07.model.entity.DeptVo">
select * from dept
</select>
</mapper>
Test
원래 namespace 작성이 필수가 아니었는데 ORM되도록 업데이트 되면서 namespace가 필수가 되었다.
DaoImpl을 작성하지 않았음에도 불구하고 DeptDao interface를 이용해서 select를 할 수 있게 된 결과값을 볼 수 있다.
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:/applicationContext.xml")
public class DeptDaoTest {
@Autowired
SqlSession sqlSession;
@Test
public void findAllTest() {
// for(DeptVo bean : sqlSession.getMapper(DeptDao.class).findAll()) {
// System.out.println(bean);
// }
assertNotNull(sqlSession.getMapper(DeptDao.class).findAll());
}
}
jackson - spring에서 List, Map같은 자료구조를 받아 return했을 때 자동으로 json형태로 변환하여 return해준다.
<!-- jackson-databind -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.13.3</version>
</dependency>
Controller
4.x버전부터는 메서드를 포함한 Mapping이 가능하다. (@GetMapping, @PostMapping, @PutMapping, @DeleteMapping)
@Inject의 경우는 @AutoWired랑 똑같으나 다른 프레임워크에서도 사용 가능한 주입 기능이다.
비동기 통신과 같이 return시 view대신 데이터를 리턴할때는 return 타입에 @ResponseBody를 붙여주면 된다.
package com.bit.sts07.controller;
import javax.inject.Inject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ...;
@Controller
@RequestMapping("/dept")
public class DeptController {
Logger log = LoggerFactory.getLogger(getClass());
@Inject
DeptService deptService;
@GetMapping("/")
public String list(Model model) {
model.addAttribute("list", deptService.selectAll());
return "dept/list";
}
@PostMapping("/")
public String add(@ModelAttribute("bean") DeptVo bean) {
log.debug(bean.toString());
deptService.insertOne(bean);
return "redirect:./";
}
// public @ResponseBody String detail(@PathVariable("1") int deptno) {
// return "msg";
// }
// 리스트, 객체를 리턴할 때 jackson 라이브러리가 있으면 자동으로 json형태로 리턴을 해준다.
// public @ResponseBody List detail(@PathVariable("num") int deptno) {
// return new ArrayList();
// }
// public @ResponseBody Map detail(@PathVariable("num") int deptno) {
// return new HashMap();
// }
@GetMapping("/{num}")
public @ResponseBody DeptVo detail(@PathVariable("num") int deptno) {
return deptService.selectOne(deptno);
}
@PutMapping("/{num}")
public @ResponseBody ResponseEntity<?> update(@RequestBody DeptVo bean) {
System.out.println(bean);
if(deptService.updateOne(bean)>0) {
return new ResponseEntity(null, HttpStatus.OK);
}
return new ResponseEntity(null, HttpStatus.INTERNAL_SERVER_ERROR);
}
@DeleteMapping("/{deptno}")
public @ResponseBody String delete(@PathVariable("deptno") int deptno) {
System.out.println("delete : " + deptno);
deptService.deleteOne(deptno);
return "";
}
}
Service - DeptDao를 구현하지 않고도 Mybatis에서 Dao를 참고하여 자동으로 메서드를 만들어준다.
package com.bit.sts07.service;
import ...;
@Service
public class DeptService {
@Autowired
SqlSession sqlSession;
public List<DeptVo> selectAll() {
return sqlSession.getMapper(DeptDao.class).findAll();
}
public DeptVo selectOne(int deptno) {
return sqlSession.getMapper(DeptDao.class).findOne(deptno);
}
@Transactional
public void insertOne(DeptVo bean) {
sqlSession.getMapper(DeptDao.class).insertOne(bean);
}
@Transactional
public int updateOne(DeptVo bean) {
return sqlSession.getMapper(DeptDao.class).updateOne(bean);
}
@Transactional
public int deleteOne(int deptno) {
return sqlSession.getMapper(DeptDao.class).deleteOne(deptno);
}
}
mybatis-config 에서 typeAlias를 지정해서 편하게 사용
<configuration>
<typeAliases>
<typeAlias type="com.bit.sts07.model.entity.DeptVo" alias="deptBean"/>
</typeAliases>
<mappers>
<mapper resource="mapper/dept-mapper.xml"/>
</mappers>
</configuration>
mapper에 SQL 구문 작성 - namespace를 반드시 지정해줘야 Dao를 구현하지 않고도 Service에서 사용할 수 있게 된다.
<mapper namespace="com.bit.sts07.model.DeptDao">
<select id="findAll" resultType="deptBean">
select * from dept
</select>
<select id="findOne" parameterType="int" resultType="deptBean">
select * from dept where deptno=#{val}
</select>
<insert id="insertOne" parameterType="deptBean">
insert into dept value(#{deptno}, #{dname}, #{loc})
</insert>
<update id="updateOne" parameterType="deptBean">
update dept set dname=#{dname}, loc=#{loc} where deptno=#{deptno}
</update>
<delete id="deleteOne" parameterType="int">
delete from dept where deptno=#{val}
</delete>
</mapper>
session을 이용한 간단 로그인/아웃 구현
Controller
@Controller
@RequestMapping("/join")
public class JoinController {
@GetMapping("/")
public String form() {
return "join/login";
}
@PostMapping("/")
public String login(@ModelAttribute("bean") DeptVo bean, HttpSession session, Model model) {
if("user1".equals(bean.getDname())
&& "test".equals(bean.getLoc())) {
session.setAttribute("result", true);
session.setAttribute("user", bean.getDname()+ "님 환영합니다.");
return "redirect:../";
}
model.addAttribute("err", "로그인 정보가 정확하지 않습니다.");
return "join/login";
}
@RequestMapping("/logout")
public String logout(HttpSession session ) {
session.invalidate();
return "redirect:../";
}
}
login.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<%@ include file="../template/header.jspf" %>
</head>
<body>
<%@ include file="../template/menu.jspf" %>
<!--
menu.jspf의 내용중...
...
<c:if test="${!sessionScope.result }">
<li><a href="${pageContext.servletContext.contextPath }/join/">Login</a></li>
</c:if>
<c:if test="${sessionScope.result }">
<li><a href="${pageContext.servletContext.contextPath }/join/logout">Logout</a></li>
</c:if>
</ul>
<p class="navbar-text navbar-right">${sessionScope.user }</p>
...
-->
<div class="page-header">
<h1>Login page<small>register</small></h1>
</div>
<div class="alert alert-danger" role="alert">${err }</div>
<form method="post">
<div class="form-group">
<input name="dname" placeholder="dname" class="form-control"/>
</div>
<div class="form-group">
<input name="loc" placeholder="loc" class="form-control"/>
</div>
<div class="form-group">
<button>로그인</button>
</div>
</form>
<script type="text/javascript">
if('${err}'=='')$('.alert').alert('close');
</script>
<%@ include file="../template/footer.jspf" %>
</body>
</html>