MVC: Model-View-Controller
Model: 데이터를 실어 보내는 역할
View: 페이지 표시
Controller: 제어
new-> Spring starter project
Type: Maven, Packaging: War or jar
Lombok, MyBatis Framework, Oracle Driver, Spring Web 체크 (처음에는 검색해야 함) =>jar를 일일히 다운받아서 lib 폴더에 복사하지 않아도 된다.
spring.datasource.driver-class-name=oracle.jdbc.driver.OracleDriver
spring.datasource.url=jdbc:oracle:thin:@localhost:1521:XE
spring.datasource.data-username=c##madang
spring.datasource.data-password=madang
server.port=8088 //포트번호는 디폴트가 8080
server.session.timeout=36000
spring.mvc.view.prefix=/WEB-INF/views/ //view name 쓸 때 경로를 직접 타이핑하지 않아도 되게 prefix를 설정
spring.mvc.view.suffix=.jsp //view name 쓸 때 jsp를 타이핑하지 않아도 되게 suffix를 설정
[프로젝트이름]Application.java : 서버 실행을 위한 메인. 여기서 실행 단추를 눌러서 서버를 실행한다.
서버 가동 후 localhost:(포트번호)로 들어가면 됨
포트번호는 기본 8080. 혹은 지정한 포트번호
com.example.demo 패키지 안에 들어있어야 어노테이션 자동 스캔이 된다. 자동 스캔을 위해서 demo 아래에 패키지들을 만들어 준다.
DB 데이터 이동 경로:
BoardMapper -> DBManager -> BoardDAO -> BoardController
패키지 이름은 소문자로
db:DB 관련 클래스나 파일들. dao:DAO. vo:VO. controller: Controller.
mybatis 홈페이지: https://mybatis.org/mybatis-3/
-> Getting started 가면 필요한 코드 example들이 있음
sql문을 정의하는 xml
Mybatis 홈페이지에 있는 example(아래)을 수정해서 사용
<?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 namespace="org.mybatis.example.BlogMapper">
<select id="selectBlog" resultType="Blog">
select * from Blog where id = #{id}
</select>
</mapper>
↓
<?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 namespace="customer">
<select id="findAll" resultType="customerVO">
select * from customer
</select>
<select id="findByCustid" resultType="customerVO">
select * from customer where custid=#{custid}
</select>
<insert id="insert" parameterType="customerVO">
insert into customer(custid,name,address,phone) values(#{custid},#{name},#{address},#{phone})
</insert>
<update id="update" parameterType="customerVO">
update customer set name=#{name}, address=#{address}, phone=#{phone} where custid=#{custid}
</update>
<delete id="delete">
delete customer where custid=#{custid}
</delete>
</mapper>
namespace: 해당 mapper의 이름 지정
<select id="" resultType="" parameterType=""></select>
id: 기능 이름을 지정 ex)findAll, findById, update, insert, ...
resultType: 리턴하는 값의 타입. (select할 때 써 준다. ResultSet에 내용이 담기는 것과 비슷함)
parameterType: 매개변수로 입력하는 값의 타입.
칼럼 이름을 변수로 지정할 경우 ${변수} (# 아님!!) (예: order by ${칼럼이름})
driver=oracle.jdbc.driver.OracleDriver
url=jdbc:oracle:thin:@localhost:1521:XE
username=c##madang
password=madang
<?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>
<properties resource="com/example/demo/db/db.properties"/>
<typeAliases>
<typeAlias type="com.example.demo.vo.BookVO" alias="bookVO"/> //별칭 설정
</typeAliases>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${driver}"/> //db.properties의 변수들이 들어감
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="com/example/demo/db/BookMapper.xml"/> // 만든 Mapper 경로를 써 줌
</mappers>
</configuration>
public class DBManager {
public static SqlSessionFactory sqlSessionFactory;
static {
String resource = "com/example/demo/db/sqlMapConfig.xml";
InputStream inputStream;
try {
inputStream = Resources.getResourceAsStream(resource);
sqlSessionFactory =
new SqlSessionFactoryBuilder().build(inputStream);
} catch (IOException e) {
e.printStackTrace();
}
}
public static List<BookVO> findAll(){
List<BookVO> list=null; //빈 리스트를 생성
SqlSession session=sqlSessionFactory.openSession(); //sqlSessionFactory를 통해 SqlSession 객체 생성
list=session.selectList("book.findAll"); // BookMapper에 있는 id가 findAll인 메소드를 호출
session.close();
return list;
}
}
public static List<CustomerVO> findAll(){
List<CustomerVO> list=null;
SqlSession session=sqlSessionFactory.openSession();
list=session.selectList("customer.findAll");
session.close();
return list;
}
public static CustomerVO findByCustid(int custid) {
CustomerVO c=new CustomerVO();
SqlSession session=sqlSessionFactory.openSession();
c=session.selectOne("customer.findByCustid",custid);
session.close();
return c;
}
public static int insert(CustomerVO c) {
SqlSession session=sqlSessionFactory.openSession();
int re=session.insert("customer.insert",c);
session.commit();
session.close();
return re;
}
public static int update(CustomerVO c) {
SqlSession session=sqlSessionFactory.openSession(true);
//autocommit true=>따로 session.commit 안 해도 됨
int re=session.insert("customer.update", c);
session.close();
return re;
}
public static int delete(int custid) {
SqlSession session=sqlSessionFactory.openSession(true);
int re=session.delete("customer.delete",custid);
session.close();
return re;
}
SqlSession session=sqlSessionFactory.openSession(true);
SqlSession 객체를 생성함과 동시에 자동으로 commit되게 하는 방법.
commit을 하지 않으면 insert나 update, delete에 성공해도 커밋이 되지 않아서 DB에 저장되지 않는다.
session.commit();
@Data //lombok. Getter, Setter, ToString 등을 자동으로 만들어 줌
public class BookVO {
private int bookid;
private String bookname;
private String publisher;
private int price;
}
@Repository
public class CustomerDAO {
public List<CustomerVO> findAll(){
return DBManager.findAll();
}
public CustomerVO findByCustid(int custid) {
return DBManager.findByCustid(custid);
}
public int insert(CustomerVO c) {
return DBManager.insert(c);
}
public int update(CustomerVO c) {
return DBManager.update(c);
}
public int delete(int custid) {
return DBManager.delete(custid);
}
}
@Controller
@RequestMapping("/insertBoard")
public class InsertBoardController {
@Controller ->컨트롤러로 지정. 클래스 시작하는 부분 위에 씀
@RequestMapping("/insertBoard") -> 이 컨트롤러가 연결되는 주소. 이 컨트롤러 안의 메소드를 실행했을 때 마지막에 이동하는 뷰 주소를 설정해 줌 (메소드마다 따로 설정할 수 있다)
updateBoardController, insertBoardController 등 기능마다 controller를 따로 만들거나 하나의 컨트롤러에 모든 기능을 다 코딩할 수도 있음.
따로 만들 경우, controller 클래스 시작 전에 @RequestMapping을 하면 모두 똑같은 view가 설정된다. (메소드마다 따로 설정해도 되긴 함)
메소드마다 get방식, post 방식 지정할 때
@RequestMapping(method=RequestMethod.GET)
@RequestMapping(method=RequestMethod.POST)
혹은
@GetMapping
@PostMapping
메소드마다 view를 따로 지정할 경우:
@RequestMapping(value="/updateBoard", method=RequestMethod.GET)
@GetMapping("/updateBoard")
public class InsertBoardController {
@Autowired
private BoardDAO dao;
public void setDao(BoardDAO dao) {
this.dao = dao;
}
or
@Setter
public class InsertBoardController {
@Autowired
private BoardDAO dao;
멤버변수로 dao를 선언
setter에 의한 의존관계를 설정하기 위해서 dao의 setter를 만들어준다. (1번처럼 직접 만들어도 되고 2번처럼 lombok의 @Setter를 써도 됨)
@Autowired-> 의존관계를 자동으로 설정한다.
ModelAndView를 사용하기 위해 객체를 생성한다.
ModelAndView mav = new ModelAndView();
view로 실어 보낼 객체를 mav에 add한다.
mav.addObject("object의 이름",object);
어떤 뷰로 갈지 주소를 입력. 설정하지 않으면 annotation 에서 설정한 뷰로 이동한다.
mav.setViewName("listBoard");
MAV 객체를 생성할 때 매개변수로 view 주소를 넣을 수도 있다. 빈 MAV를 생성하고 setViewName을 하는 것과 같음.
ModelAndView mav=new ModelAndView("listBoard");
ModelAndView mav=new ModelAndView("redirect:/listBoard");
updateBoard에서 데이터베이스 레코드 업데이트 성공 시 listBoard 페이지로 보내려고 한다. 이 때 redirect 없이 listBoard 를 view페이지로 설정하게 되면 빈 페이지가 나온다. 왜냐하면 listBoard 메소드에서 상태유지된 객체(addObject로 추가된 객체)가 updateBoard 메소드에는 없기 때문. 상태유지해서 이동하려면 redirect:/ 를 view name 앞에 붙여줘야 한다.
메소드 리턴타입을 ModelAndView로 설정하고 마지막에 mav를 리턴해줘야 한다.
@RequestMapping("/listBook")
public ModelAndView list() {
ModelAndView mav=new ModelAndView();
mav.addObject("list", dao.findAll());
mav.setViewName("list");
return mav;
}
view를 설정할 필요가 없을 경우:
ModelAndView 대신 Model을 사용해도 된다.
메소드 리턴값을 void로 설정하고 매개변수에 Model model을 넣고,
model.addAttribute()를 한다. (mav.addObject와 똑같은 기능)
@RequestMapping("/listBook") //여기에서 지정한 view name을 바꿀 필요가 없을 경우
public void list(Model model) {
model.addAttribute("list",dao.findAll());
}
webapp/WEB-INF/views
<%@ taglib uri="[http://java.sun.com/jsp/jstl/core](http://java.sun.com/jsp/jstl/core)" prefix="c"%>
<c:forEach var="b" items="${list }"> //list 안의 요소(vo) 하나하나를 b라고 정하고 forEach 반복문으로 하나씩 불러오기
${b.bookname }<br> //b의 bookname 속성을 출력
</c:forEach>