Spring 3.0
eclipse perspective 설정을 spring으로 변경
프로젝트 생성하자마자 실행하여 Hello, world 볼 수 있는데 한글이 깨지는 것은 JSP 문제다. 아래 코드를 jsp에 추가하면된다.
<%@ page pageEncoding="utf-8" %>
servlet-context.xml
기본적으로 handller mapping은 따로 되어있지 않고 어노테이션을 이용할 수 있도록 해두었고 view resolver 되어있음
그래서 매핑을 하려고 servlet-context를 수정할 필요 없이 어노테이션을 이용하여 매핑을 해야함
최대한 손댈 필요 없도록 만들었던 것이 특징이다.
<!-- Enables the Spring MVC @Controller programming model -->
<annotation-driven />
...
<!-- Resolves views selected for rendering by @Controllers to .jsp resources in the /WEB-INF/views directory -->
<beans:bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<beans:property name="prefix" value="/WEB-INF/views/" />
<beans:property name="suffix" value=".jsp" />
</beans:bean>
Controller
@org.springframework.stereotype.Controller
public class Ex01Controller implements Controller {
@RequestMapping("/ex01.do")
@Override
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
return new ModelAndView("ex01");
}
}
Spring 3.0은 POJO 지향으로 개발되었기 때문에 개발자 입장에서도 편하고 spring 입장에서도 가벼운 장점이 있다.
어노테이션을 이용하면 Controller 인터페이스를 구현하지 않아도 사용이 가능하다.
@RequestMapping을 메소드에 달기 때문에 메소드명도 자유롭게 사용 가능.
그러므로 하나의 컨트롤러에 여러개의 URL매핑을 할 수 있게 된다.
return 타입도 자유, 파라미터도 자유
@Controller
public class Ex02Controller{
@RequestMapping("/ex02.do")
public ModelAndView ex02(HttpServletRequest request, HttpServletResponse response) throws Exception {
return new ModelAndView("ex02");
}
@RequestMapping("/ex03.do")
public ModelAndView ex03(HttpServletRequest request, HttpServletResponse response) throws Exception {
return new ModelAndView("ex03");
}
@RequestMapping("/ex04.do")
public String ex04(HttpServletRequest request, HttpServletResponse response) throws Exception {
return "ex04";
}
@RequestMapping("/ex05.do")
public String ex05() {
return "ex05";
}
}
단, 아무 클래스에나 어노테이션을 단다고해서 컨트롤러가 되는 것은 아니다.
servlet-context.xml에서 설정되어있는 package의 하위 경로의 객체들을 scan한다.
<context:component-scan base-package="com.bit.sts04" />
클래스에도 @RequestMapping을 달 수 있는데 추가적으로 경로를 하나 더 달 수 있다.
단 클래스에 달았다고해서 메서드에 안달면 안된다. 메서드에는 필수.
@Controller
@RequestMapping("/lec01")
public class Ex03Controller {
@RequestMapping("/ex06.do")
public String ex06() {
return "ex01";
}
}
>>> /lec01/ex06.do 로 호출 가능
모든 요청이 DispatcherSevlet을 타도록 되어있기 때문에 jsp에서 css,img 등을 가져오기 위해선
IO를 통해서 직접 가져오는 방법도 있겠지만 servlet-context.xml에서 처리를 할 수 있다.
기본 설정은 직접 불러올 파일들을 webapp의 resouces 아래에 넣으면 되도록 설정 되어있다.
이러한 방식은 실제 URL을 파악할 수 없기 때문에 보안의 장점이 있다.
<!-- Handles HTTP GET requests for /resources/** by efficiently serving up static resources in the ${webappRoot}/resources directory -->
<resources location="/resources/" mapping="/resources/*"/>
<resources location="/resources/imgs/" mapping="/images/*"/>
<img alt="" src="resources/imgs/logo.png"/>
<img alt="" src="images/logo.png"/>
@RequestMapping에서 메서드 속성을 지정해줄 수 있다.
@RequestMapping(value="/ex12", method= {RequestMethod.GET,RequestMethod.POST})
public String ex11() {
return "ex01";
}
@RequestMapping(value="/ex12", method= {RequestMethod.POST})
public String ex12() {
return "ex02";
}
@RequestParam 어노테이션을 이용하면 파라미터를 간단하게 받을 수 있다. parseInt 과정도 필요없이 타입에 맞게 가져온다.
변수명을 같게하면 속성정의를 생략할 수 있다. @RequestParam 자체도 생략 가능하다. 순서 상관 X
@RequestMapping(value="/ex12", method= {RequestMethod.POST})
public String ex12(
@RequestParam("dname") String name,
@RequestParam int deptno,
String loc) {
...
return "ex02";
}
값을 전달하기 위해서는 HttpServletRequest 객체 혹은 Model 객체를 받아와서 사용해야한다.
@RequestMapping(value="/ex12", method= {RequestMethod.POST})
public String ex12(String dname, int deptno, /*HttpServletRequeset req*,/ Model model ) {
// req.setAttribute("dname", dname);
// req.setAttribute("deptno", deptno);
model.addAttribute("dname", dname);
model.addAttribute("deptno", deptno);
return "ex02";
}
@PathVariable 어노테이션을 이용하면 url을 통해 값을 받아낼 수 있다 ex)/ex13/abcd/1234 로 호출하게 되면 abcd와 1234를 가져온다.
@PathVariable은 생략이 불가능하다. 속성까진 생략 가능하다.
@RequestMapping("/ex13/{msg}/{num}")
public String ex13(
@PathVariable("msg") String msg,
@PathVariable int num) {
...
return "ex03";
}
@ModelAttribute를 이용해서 객체를 전달 할 수 있다.
변수명이 동일하더라도 속성 생략은 불가능하다.
AOP에서 bean생성하고 값 넣어주던 작업을 어노테이션하나로 할 수 있게 된 것.
@RequestMapping("ex14")
public String ex14(@ModelAttribute("bean") DeptVo bean) {
bean.setDeptno(2222);
bean.setDname("test3");
bean.setLoc("test");
return "ex04";
}
docker를 이용해서 mysql 사용하기
docker pull mysql
docker run -p 3306:3306 --name mysql8 -e MYSQL_ROOT_PASSWORD=mysql -e MYSQL_DATABASE=lecture -e MYSQL_USER=scott -e MYSQL_PASSWORD=tiger -d mysql
접속확인 및 dummy data 추가 필요
pom.xml에 dependency 추가 (spring jdbc, mysql) root-context.xml에 DB 연결 설정 추가
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://192.168.99.000:3306/lecture"/>
<property name="username" value="scott"/>
<property name="password" value="tiger"/>
</bean>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"/>
</bean>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<bean id="deptDao" class="com.bit.sts04.model.DeptDaoImpl">
<property name="jdbcTemplate" ref="jdbcTemplate"/>
<property name="transactionManager" ref="transactionManager"></property>
</bean>
CRUD 구현
DeptDao interface
package com.bit.sts04.model;
import java.util.List;
public interface DeptDao {
List<DeptVo> findAll();
DeptVo findOne(int key);
void insertOne(DeptVo bean);
int updateOne(DeptVo bean);
int deleteOne(int key);
}
DeptDaoImpl
public class DeptDaoImpl extends JdbcDaoSupport implements DeptDao{
PlatformTransactionManager transactionManager;
public void setTransactionManager(PlatformTransactionManager transactionManager) {
this.transactionManager = transactionManager;
}
@Override
public List<DeptVo> findAll() {
String sql = "select * from dept";
return getJdbcTemplate().query(sql, new RowMapper<DeptVo>() {
@Override
public DeptVo mapRow(ResultSet rs, int rowNum) throws SQLException {
return new DeptVo(rs.getInt("deptno"), rs.getString("dname"), rs.getString("loc"));
}
});
}
@Override
public DeptVo findOne(int key) {
String sql = "select * from dept where deptno=?";
return getJdbcTemplate().queryForObject(sql, new RowMapper<DeptVo>() {
@Override
public DeptVo mapRow(ResultSet rs, int rowNum) throws SQLException {
return new DeptVo(rs.getInt("deptno"), rs.getString("dname"), rs.getString("loc"));
}
}, key);
}
@Override
public void insertOne(final DeptVo bean) {
final String sql = "UPDATE dept_seq SET num=num+1;";
final String sql2 = "INSERT INTO dept VALUE((SELECT * from dept_seq), CONCAT(?,(SELECT * from dept_seq)), ?);";
TransactionDefinition definition = new DefaultTransactionAttribute();
TransactionStatus status = transactionManager.getTransaction(definition);
try {
PreparedStatementCreator psc = new PreparedStatementCreator() {
@Override
public PreparedStatement createPreparedStatement(Connection con) throws SQLException {
System.out.println(con.hashCode()); // 같은 객체인지 확인
return con.prepareStatement(sql);
}
};
getJdbcTemplate().update(psc);
psc = new PreparedStatementCreator() {
@Override
public PreparedStatement createPreparedStatement(Connection con) throws SQLException {
System.out.println(con.hashCode()); // 같은 객체인지 확인
PreparedStatement pstmt = con.prepareCall(sql2);
pstmt.setString(1, bean.getDname());
pstmt.setString(2, bean.getLoc());
return pstmt;
}
};
getJdbcTemplate().update(psc);
transactionManager.commit(status);
} catch (Exception e) {
transactionManager.rollback(status);
}
}
@Override
public int updateOne(DeptVo bean) {
String sql = "update dept set dname=?, loc=? where deptno=?";
return getJdbcTemplate().update(sql, bean.getDname(), bean.getLoc(), bean.getDeptno());
}
@Override
public int deleteOne(int key) {
String sql = "delete from dept where deptno=?";
return getJdbcTemplate().update(sql, key);
}
}
Controller
@Controller
public class RootController {
@Autowired
DeptDao deptDao;
@RequestMapping("/")
public String index() {
return "index";
}
@RequestMapping("/dept/list")
public String list(Model model) {
model.addAttribute("list", deptDao.findAll());
return "dept/list";
}
@RequestMapping(value="/dept/add", method = RequestMethod.GET)
public String add() {
return "dept/add";
}
@RequestMapping(value="/dept/add", method = RequestMethod.POST)
public String add(String dname, String loc) {
deptDao.insertOne(new DeptVo(0, dname, loc));
return "redirect:list";
}
@RequestMapping("/dept/detail")
public String detail(int deptno, Model model) {
model.addAttribute("bean",deptDao.findOne(deptno));
return "dept/detail";
}
@RequestMapping(value = "/dept/update", method = RequestMethod.POST)
public String edit(@ModelAttribute DeptVo bean) {
deptDao.updateOne(bean);
return "redirect:list";
}
@RequestMapping(value = "/dept/delete", method = RequestMethod.POST)
public String delete(int deptno) {
deptDao.deleteOne(deptno);
return "redirect:list";
};
}
spring ibatis
의존성 추가
<!-- https://mvnrepository.com/artifact/org.apache.ibatis/ibatis-sqlmap -->
<dependency>
<groupId>org.apache.ibatis</groupId>
<artifactId>ibatis-sqlmap</artifactId>
<version>2.3.4.726</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-ibatis -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-ibatis</artifactId>
<version>2.0.8</version>
</dependency>
SqlMapConfig.xml, Query.xml
------------------ SqlMapConfig.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE sqlMapConfig PUBLIC "-//ibatis.apache.org//DTD SQL Map Config 2.0//EN" "http://ibatis.apache.org/dtd/sql-map-config-2.dtd">
<sqlMapConfig>
<sqlMap resource="Query.xml"/>
</sqlMapConfig>
------------------- Query.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE sqlMap
PUBLIC "-//ibatis.apache.org//DTD SQL Map 2.0//EN"
"http://ibatis.apache.org/dtd/sql-map-2.dtd">
<sqlMap>
<select id="selectAll" resultClass="com.bit.sts04.model.DeptVo">
select * from dept order by deptno desc
</select>
<insert id="insertOne" parameterClass="com.bit.sts04.model.DeptVo">
insert into dept values (#deptno#,#dname#,#loc#)
</insert>
<select id="selectOne" parameterClass="int" resultClass="com.bit.sts04.model.DeptVo">
select * from dept where deptno=#val#
</select>
<update id="updateOne" parameterClass="com.bit.sts04.model.DeptVo">
update dept set dname=#dname#, loc=#loc# where deptno=#deptno#
</update>
<delete id="deleteOne" parameterClass="int">
delete from dept where deptno=#val#
</delete>
</sqlMap>
DeptDaoIbatisImpl
package com.bit.sts04.model;
import ...
public class DeptDaoIbatisImpl extends SqlMapClientDaoSupport implements DeptDao {
@Override
public List<DeptVo> findAll() {
return getSqlMapClientTemplate().queryForList("selectAll");
}
@Override
public DeptVo findOne(int key) {
return (DeptVo) getSqlMapClientTemplate().queryForObject("selectOne",key);
}
@Override
public void insertOne(DeptVo bean) {
}
@Override
public int updateOne(DeptVo bean) {
return getSqlMapClientTemplate().update("updateOne",bean);
}
@Override
public int deleteOne(int key) {
return getSqlMapClientTemplate().delete("deleteOne",key);
}
}
root-context.xml
<bean id="sqlMapClient" class="org.springframework.orm.ibatis.SqlMapClientFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="configLocation" value="classpath:/SqlMapConfig.xml"/>
</bean>
<bean id="sqlMapClientTemplate" class="org.springframework.orm.ibatis.SqlMapClientTemplate">
<property name="sqlMapClient" ref="sqlMapClient"/>
</bean>
<bean id="deptDao" class="com.bit.sts04.model.DeptDaoIbatisImpl">
<property name="sqlMapClientTemplate" ref="sqlMapClientTemplate"/>
</bean>
'회고록(TIL&WIL)' 카테고리의 다른 글
TIL 2023.03.08 Spring framework 3.X(docker_volume, lombok, @Aspectj, Transaction, mybatis) (0) | 2023.03.09 |
---|---|
TIL 2023.03.07 Spring framework 3.X (STS 3.X, AOP, Service, docker-volume) (0) | 2023.03.07 |
TIL 2023.03.03 docker tomcat 배포 (0) | 2023.03.06 |
TIL 2023.03.02 Spring framework ver 2.X (IoC-DI, AOP, Junit) (0) | 2023.03.06 |
TIL 2023.02.27 Spring framework ver 2.X (0) | 2023.02.27 |