Edit Starter
application.properties
#데이터 소스 설정, DataSource, JdbcTemplate 자동생성 이후 @Autowired로 자동주입 사용함
spring.datasource.driver-class-name=oracle.jdbc.OracleDriver
spring.datasource.url=jdbc:oracle:thin:@localhost:1521:xe
spring.datasource.username=scott
spring.datasource.password=tiger
DeptDAO.java
에 DataSource를 자동주입 받아서 연동되었는지 getConnection()으로 주소를 찍어본 후 select 처리를 한다.
@Repository("dao")
public class DeptDAO {
@Autowired
DataSource dataSource;
public List<DeptDTO> select() {
List<DeptDTO> list = new ArrayList<DeptDTO>();
Connection con = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
con = dataSource.getConnection();
pstmt = con.prepareStatement("select * from dept");
rs = pstmt.executeQuery();
while(rs.next()) {
int n = rs.getInt("deptno");
String n2 = rs.getString("dname");
String n3 = rs.getString("loc");
DeptDTO dto = new DeptDTO(n, n2, n3);
list.add(dto);
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
try {
if(rs!=null)rs.close();
if(pstmt!=null)pstmt.close();
if(con!=null)con.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
return list;
}
}
JPA는 자바 진영에서 ORM
(Object-Relational-Mapping) 기술 표준으로 사용되는 인터페이스의 모음이다.
실제적으로 구현된 것이 아닌, 구현된 클래스들과 매핑을 해주기 위해 사용되는 프레임워크이다.
대표적 오픈소스는 Hibernate
를 사용한다.
application class
와 RDB
(Relational Database)의 테이블을 매핑(연결)한다는 뜻이며,application의 객체를 RDB테이블에 자동으로 영속화 해주는 것이라고 보면된다.
- 장점
- SQL문이 아니고 Method를 통해 DB를 조작할 수 있어서, 개발자가 객체 모델을 이용하여 비즈니스 로직을 구성하는 데만 집중할 수 있다.
- Query와 같이 필요한 선언문, 할당 등의 부수적인 코드가 줄어들어, 각종 객체에 대한 코드를 별도로 작성하여 코드의 가독성을 높인다.
- 오직 객체지향적 접근만 고려하면 되기 떄문에 생산성이 증가한다.
- 매핑하는 정보가 Class로 명시 되었기 때문에 ERD를 보는 의존도를 낮출 수 있다.
- 따라서 유지보수 및 리팩토링에 유리하다.
- MySQL에서 Oracle로 변환한다고 하면 새로 쿼리를 짜야하는 경우가 생기는데, ORM을 사용하면 쿼리를 수정할 필요가 없다.
- 단점
- 프로젝트 규모가 크고 복잡하여 설계가 잘못된 경우, 속도 저하 및 일관성을 무너뜨리는 문제점이 생길 수 있다.
- 복잡하고 무거운 Query는 속도를 위해 별도의 튜닝이 필요하기 때문에 결국 SQL문을 써야한다.
- 학습 비용이 비싸다.
JPA를 사용하는 이유는 반복적인 CRUD SQL을 처리해주기 때문이다.
따라서 SQL이 아닌 객체 중심으로 개발할 수 있다는 것이고, 이는 결국 생산성이 좋아지고 유지보스가 수월해진다.
JPA는 패러다임의 불일치도 해결하였다.
-> Java는 상속관계(부모클래스와 자식클래스의 관계) 가 존재하는데 DB에서는 이런 객체의 상속관계를 지원하지 않는다. 이런 상속관계를 JPA는 Table 슈퍼타입 서브타입 관계
방식으로 해결하였고, 연관관계를 테이블 연관관계
방식으로 해결하였다.
추가적으로 알아둬야 할 것은, 스프링에서 흔히 사용하는 것으로 알고있는 JPA는, JPA를 이용하는 spring-data-jpa 프레임워크이지 JPA는 아니다.
-출처: 자바 ORM 표준 JPA 프로그래밍 / 저자: 김영한 -
h2 DB와 연결하기 위해 필요한 dependency를 추가한다.
application.properties
에서datasource와 jpa코드를 넣어준다.
spring.datasource.url=jdbc:h2:tcp://localhost/~/test
spring.datasource.driver-class-name=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=
#ddl-auto기능 create, create-drop, none, update, validate
#테이블 자동생성
spring.jpa.hibernate.ddl-auto=create
#SQL실행 정보 출력
spring.jpa.show-sql=true
#database정보
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
UserDTO
dao에서 JpaUserRepository를 쓰기위해
@Entity와 @Id, @GeneratedValue를 설정해준다.
@Entity
public class User {
//Id 컬럼지정, DB서버의 키 값을 설정
@Id //기본키 설정
@GeneratedValue(strategy = GenerationType.IDENTITY)
//기본키 자동 증가
private int id;
private String name;
private String address;
.
.
.
}
UserService.java
@Service("service")
public class UserServiceImp implements UserService{
@Autowired
JpaUserRepository repository;
@Override
public List<User> findAll() {
return repository.findAll();
}
.
.
}
JpaUserRepository
JpaRepository<dto, Integer>
형식으로 extends하면 Spring에서 CRUD 함수를 자동구현하여 처리하게한다.
public interface JpaUserRepository extends JpaRepository<User, Integer>{
// JapUserRepository를 이용하여 Spring에서 자동구현 해줌
// 구현을 위한 코드는 개발자가 아닌 Spring에서 처리함
// User 클래스를 Entity로 지정하고, Id/Key의 데이터 타입을 Integer로 정함
// CRUD
// findByAll, findById, save(insert, update), deleteById
// 함수 자동구현
}
@SpringBootApplication
@SpringBootApplication
public class Boot12Db1SpringDataJdbc1H2EmbeddedApplication {
public static void main(String[] args) {
ApplicationContext ctx = SpringApplication.run(Boot12Db1SpringDataJdbc1H2EmbeddedApplication.class, args);
UserService service = ctx.getBean("service",UserService.class);
//h2 서버 가동 후 실행할 것
//insert 후 실행함
//1. 데이터 insert
User user = service.save(new User("홍길동", "서울"));
User user2 = service.save(new User("이순신", "123"));
System.out.println("insert 데이터 : " + user);
user.setAddress("Seoul");
System.out.println("update 전 데이터:"+ user);
//2. update
User upuser = service.update(user);
System.out.println("update 후 데이터:"+ upuser);
//3. 특정 데이터
Optional<User> op = service.findById(1);
System.out.println("find by Id: " + op.get());
System.out.println("==========================");
service.delete(1);
List<User> list = service.findAll();
for (User use : list) {
System.out.println(use);
}
}
자동 생성된 함수를 통해 CRUD 성공.
h2와 동일하고 application.properties
설정에만 차이가 있다.
#데이터 소스 설정
spring.datasource.driver-class-name=oracle.jdbc.OracleDriver
spring.datasource.url=jdbc:oracle:thin:@localhost:1521:xe
spring.datasource.username=scott
spring.datasource.password=tiger
#최초 create, 이후 none으로 변경
spring.jpa.hibernate.ddl-auto=create
spring.jpa.generate-ddl=false
spring.jpa.show-sql=true
spring.jpa.database=oracle
spring.jpa.database-platform=org.hibernate.dialect.Oracle10gDialect
- Model : 어플리케이션의 데이터와 비즈니스 로직을 담는 객체이다.
- View : Model의 정보를 사용자에게 표시한다. 하나의 Model을 다양한
View에서 사용할 수 있다.- Controller : Model과 View의 중계역할을 담당한다. 사용자의 요청을 받아
Model에 변경된 상태를 반영하고 응답을 위한 View를 선택한다.
SpringBoot에서는 자동으로 TransactionManager가 활성화된다.
dependency 설정
application.properties
datasource, mybatis설정
#데이터 소스 설정 . SqlSessionTemplate 자동생성
spring.datasource.driver-class-name=oracle.jdbc.OracleDriver
spring.datasource.url=jdbc:oracle:thin:@localhost:1521:xe
spring.datasource.username=scott
spring.datasource.password=tiger
#mybatis 설정
mybatis.mapper-locations=com/example/mapper/DeptMapper.xml
#mapper가 여러 개인 경우 com/example/mapper/*.xml 처리
mybatis.type-aliases-package=com.example.dto
Mapper와 DTO 생성.
DBOracleDAO
@Repository("dao")
public class DBOralceDAO implements DBDao{
@Override
public List<Dept> list(SqlSessionTemplate session) {
return session.selectList("list");
//application.properties에서 namespace 경로지정을 했기 때문에 생략가능
}
@Override
public int insert(SqlSessionTemplate session, Dept dto) {
return session.insert("DeptMapper.insert",dto);
}
@Override
public int update(SqlSessionTemplate session, Dept dto) {
return session.update("DeptMapper.update",dto);
}
@Override
public int delete(SqlSessionTemplate session, int deptno) {
return session.delete("DeptMapper.delete",deptno);
}
}
DBDao
public interface DBDao {
public List<Dept> list(SqlSessionTemplate session);
public int insert(SqlSessionTemplate session, Dept dto);
public int update(SqlSessionTemplate session, Dept dto);
public int delete(SqlSessionTemplate session, int deptno);
}
DBOracleService
@Service("service")
public class DBOracleService implements DBService{
@Autowired
DBDao dao;
@Autowired
SqlSessionTemplate session;
@Override
public List<Dept> list(){
return dao.list(session);
}
@Override
public int insert(Dept dto) {
return dao.insert(session, dto);
}
@Override
public int update(Dept dto) {
return dao.update(session, dto);
}
@Override
public int delete(int deptno) {
return dao.delete(session, deptno);
}
}
DBService
public interface DBService {
List<Dept> list();
int insert(Dept dto);
int update(Dept dto);
int delete(int deptno);
}
SpringBootApplication
@SpringBootApplication
public class Boot12Db3Mybatis2Oracle11gApplication {
public static void main(String[] args) {
ApplicationContext ctx = SpringApplication.run(Boot12Db3Mybatis2Oracle11gApplication.class, args);
DBService service = ctx.getBean("service",DBService.class);
}
}
웹프로젝트(MVC) 순서
1. pom.xml => spring web, dev tool 추가
2. jsp 사용 => 디펜던시 2개 명시적 추가
3. src 서브 폴더 생성 => main/webapp/WEB-INF/view 폴더 명시적 생성(jsp 사용 폴더 명시적 생성)
4. application.properties 환경설정
- 포트번호
- 프로젝트 주소
- 뷰 resolver 설정 + DB 설정(datasource, mybatis 설정(mapper, alias)
5. controller작성(com.example의 서브 패키지에 생성)
=> /app/main => main.jsp 호출
resources/static이 css, image 등 들어가는 기본 폴더. ( application-properties
에 spring.mvc.static-path-pattern=/resources/*
를 써줘야함)
SpringBootApplication과 동일한 서브파일에 컨트롤러를 만들어 다음과 같이 list를 가져올 수 있다.
@Controller
public class MainController {
@Autowired
private DBService service;
@RequestMapping("/list")
public ModelAndView list() {
ModelAndView m = new ModelAndView();
List<Dept> list = service.list();
System.out.println(list);
m.addObject("list",list);
m.setViewName("list");
return m;
}
}
메서드 레벨에 @ResponseBody가 부여되면 그 메서드가 리턴하는 객체는 뷰를 통해 결과를 만들어내는 모델로 사용되는 대신, 메시지 컨버터를 통해 바로 HTTP응답의 메시지 본문으로 전환된다.
근본적으로 @RequestBody
나 @ResponseBody
는 XML
이나 JSON
과 같은 메시지 기반의 커뮤니케이션을 위해 사용된다.
@RequestMapping(“/hello”)
@ResponseBody
public String hello(){
return “<html><body>Hello</body></html>”);
}
--> 이 코드에서 @ResponseBody가 없다면 String 타입의 리턴값은 뷰 이름으로 인식된다. 그러나 있기 때문에 HttpServletResponse의 출력 스트림으로 동작한다.
Controller
@Controller
public class MainController {
@RequestMapping("/")
public String main() {
return "main";
}
@RequestMapping("/aaa")
public @ResponseBody Login aaa(Login login) {
return login;
}
@RequestMapping("/bbb")
public @ResponseBody ArrayList<Login> bbb(@RequestBody List<Login> login) {
System.out.println(login);
System.out.println(login.get(0).getUserid());
System.out.println(login.get(0).getPasswd());
ArrayList<Login> list = new ArrayList<Login>();
list.add(new Login(login.get(0).getUserid(),login.get(0).getPasswd()));
list.add(new Login(login.get(1).getUserid(),login.get(1).getPasswd()));
list.add(new Login(login.get(2).getUserid(),login.get(2).getPasswd()));
return list;
}
@RequestMapping("/ccc")
@ResponseBody
public HashMap<String, ArrayList<Login>> ccc(){
HashMap<String, ArrayList<Login>> map = new HashMap<String, ArrayList<Login>>();
ArrayList<Login> list = new ArrayList<Login>();
list.add(new Login("홍길동1", "20"));
list.add(new Login("홍길동2", "30"));
list.add(new Login("홍길동3", "40"));
ArrayList<Login> list2 = new ArrayList<Login>();
list2.add(new Login("유관순1", "20"));
list2.add(new Login("유관순2", "30"));
list2.add(new Login("유관순3", "40"));
map.put("one", list);
map.put("two", list2);
return map;
}
}
main.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>
</head>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.js"></script>
<script type="text/javascript">
$(function(){
$("#aaa").on("click",function(){
$.ajax({
type: "get",
url: "aaa", //넘겨줄 URL 주소
dataType: "text", //받아오는 데이터 타입
data:{
userid:"홍길동",
passwd:"1234"
},
success: function(data, status, xhr){
console.log(data);
$("#result").text(data);
},
error: function(xhr, status, error){
console.log("error",error);
console.log("xhr",xhr.status);
console.log("데이터를 가져올 수 없습니다.")
}
}); //end ajax
});
$("#bbb").on("click",function(){
$.ajax({
type: "post",
url: "bbb", //넘겨줄 URL 주소
dataType: "json", //받아오는 데이터 타입
headers:{
"Content-Type":"application/json"
},
data:JSON.stringify(
[
{userid:"홍기동1", passwd:"20"},
{userid:"홍기동2", passwd:"30"},
{userid:"홍기동3", passwd:"40"}
]
),
success: function(data, status, xhr){
console.log(data);
$("#result").text(data[0].userid+"\t"+data[0].passwd+"\n");
$("#result").append(data[1].userid+"\t"+data[1].passwd+"\n");
$("#result").append(data[2].userid+"\t"+data[2].passwd+"\n");
},
error: function(xhr, status, error){
console.log("error",error);
console.log("xhr",xhr.status);
console.log("데이터를 가져올 수 없습니다.")
}
}); //end ajax
});
$("#ccc").on("click",function(){
$.ajax({
type: "post",
url: "ccc", //넘겨줄 URL 주소
dataType: "json", //받아오는 데이터 타입
success: function(data, status, xhr){
var stringJSON = JSON.stringify(data); // check your object structure for serializability!
for(let i of data.one){
console.log(i.userid + "\t" +i.passwd);
}
for(let i of data.two){
console.log(i.userid + "\t" +i.passwd);
}
$("#result").text(stringJSON);
// console.log(stringJSON);
},
error: function(xhr, status, error){
console.log("error",error);
console.log("xhr",xhr.status);
console.log("데이터를 가져올 수 없습니다.")
}
}); //end ajax
});
})
</script>
<body>
<button id="aaa">aaa호출: Login</button><br>
<button id="bbb">bbb호출: ArrayList</button><br>
<button id="ccc">ccc호출: HashMap</button><br>
<div id="result"></div>
</body>
</html>
파라미터화 된 URL경로를 가능하게 하기 위해 해당 어노테이션을 제공한다.
@Controller
public class MainController {
@RequestMapping("/")
public String main() {
return "main";
}
@GetMapping("/board/name/{xxx}")
public String aaa(@PathVariable("xxx") String name) {
System.out.println("/board/name/{xxx} : " + name);
return "main";
}
@GetMapping("/board2/name/{name}/age/{age}")
public String aaa(@PathVariable("name") String name, @PathVariable("age") String age) {
System.out.println("/board/name/{name} : " + name);
System.out.println("/board/name/{age} : " + age);
return "main";
}
}
<%@ 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>
</head>
<body>
<h1>main.jsp</h1>
<a href="/app/board/name/홍길동">board</a><br>
<a href="/app/board2/name/이순신/age/20">board2</a><br>
</body>
</html>
@Controller + @ResponseBody 이다.
비동기 처리를 위임하는 전용 controller일때 사용한다.
RestController
@RestController //@Controller+@ResponseBody
public class TestController {
@RequestMapping("/aaa")
public Login aaa() {
Login dto = new Login("aaaa", "1234");
return dto;
}
@RequestMapping("/bbb")
public ArrayList<Login> bbb() {
Login dto = new Login("asdf", "1234");
Login dto2 = new Login("eeee", "999");
Login dto3 = new Login("gsfasf", "777");
ArrayList<Login> list = new ArrayList<Login>();
list.add(dto);
list.add(dto2);
list.add(dto3);
return list;
}
@RequestMapping("/ccc")
public String ccc() {
String str = "홍길동";
return str;
}
@RequestMapping("/ddd")
public String ddd() {
String mesg = "<h1>Hello 안녕하세요</h1>";
return mesg;
}
@RequestMapping("/eee")
public String eee() {
String mesg = "<person><name>홍길동</name><age>20</age></person>";
return mesg;
}
}
main.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>
</head>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.js"></script>
<script type="text/javascript">
$(function(){
$("#a").on("click",function(){
$.ajax({
type: "get",
url: "aaa", //넘겨줄 URL 주소
dataType: "json", //받아오는 데이터 타입
success: function(data, status, xhr){
console.log(data);
$("#result").text(data.userid +"\t"+data.passwd);
},
error: function(xhr, status, error){
console.log("error",error);
console.log("xhr",xhr.status);
console.log("데이터를 가져올 수 없습니다.")
}
}); //end ajax
});
$("#b").on("click",function(){
$.ajax({
type: "post",
url: "bbb", //넘겨줄 URL 주소
dataType: "json", //받아오는 데이터 타입
success: function(data, status, xhr){
console.log(data);
$("#result").text(data[0].userid+"\t"+data[0].passwd+"\n");
$("#result").append(data[1].userid+"\t"+data[1].passwd+"\n");
$("#result").append(data[2].userid+"\t"+data[2].passwd+"\n");
},
error: function(xhr, status, error){
console.log("error",error);
console.log("xhr",xhr.status);
console.log("데이터를 가져올 수 없습니다.")
}
}); //end ajax
});
$("#c").on("click",function(){
$.ajax({
type: "post",
url: "ccc", //넘겨줄 URL 주소
dataType: "text", //받아오는 데이터 타입
success: function(data, status, xhr){
$("#result").text(data);
},
error: function(xhr, status, error){
console.log("error",error);
console.log("xhr",xhr.status);
console.log("데이터를 가져올 수 없습니다.")
}
}); //end ajax
});
$("#d").on("click",function(){
$.ajax({
type: "post",
url: "ddd", //넘겨줄 URL 주소
dataType: "html", //받아오는 데이터 타입
success: function(data, status, xhr){
$("#result").html(data);
},
error: function(xhr, status, error){
console.log("error",error);
console.log("xhr",xhr.status);
console.log("데이터를 가져올 수 없습니다.")
}
}); //end ajax
});
$("#e").on("click",function(){
$.ajax({
type: "post",
url: "eee", //넘겨줄 URL 주소
dataType: "xml", //받아오는 데이터 타입
success: function(data, status, xhr){
console.log(data);
$("#result").text($(data).find("name").text()+'\t'
+$(data).find("age").text());
},
error: function(xhr, status, error){
console.log("error",error);
console.log("xhr",xhr.status);
console.log("데이터를 가져올 수 없습니다.")
}
}); //end ajax
});
})
</script>
<body>
<button id="a">LoginDTO</button>
<button id="b">ArrayList</button>
<button id="c">String</button>
<button id="d">html</button>
<button id="e">xml</button>
<div id="result"></div>
</body>
</html>
SpringBoot는 원래 jsp가 아닌 Thymeleaf를 권장한다.
help-Install New Software에서
http://www.thymeleaf.org/eclipse-plugin-update-site
링크를 추가하여 설치한다.
html 생성 기본 경로는 src/main/resources/templates 이다.
값을 다음과 바인딩시킨다.
Controller
@Controller
public class MainController {
//http://www.thymeleaf.org/eclipse-plugin-update-site
//help - install new software
@Autowired
ServletContext application;
//1. 기본
@GetMapping("/")
public String m() {
return "main"; // /resources/templates/main.html
}
//2. 바인딩 - ${...}
@GetMapping("/a2")
public String a2(Model m, HttpSession session, String userid) {
System.out.println("a2 userid= "+userid);
m.addAttribute("username", "request홍길동");
session.setAttribute("username", "session홍길동");
application.setAttribute("username", "application홍길동");
return "main2";
}
}
main.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org"> <!-- 해당 주소를 설정해줘야 한다. -->
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<h1>main2.html</h1>
<p th:text="'홍길동'"></p>
<p th:text="${username}"></p>
<p th:text="${session.username}"></p>
<p th:text="${application.username}"></p>
</body>
</html>
${...}
#{...}
//3. I18N.. #{....}
@GetMapping("/a3")
public String a3(Locale xxx) {
System.out.println("current locale xxx: "+xxx);
return "main3"; //main3.html
}
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<h1>main3.html</h1>
<p th:text="#{hello}"></p>
</body>
</html>
*{...}
//4, 객체 속성 .. *{...}, ${...}
@GetMapping("/a4")
public ModelAndView a4() {
ModelAndView mav = new ModelAndView();
mav.addObject("user", new User("홍길동", 20));
mav.setViewName("main4"); //main4.html
return mav; //main4.html
}
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<h1>main4.html</h1>
<p th:text="*{user.username}"></p>
<p th:text="*{user.age}"></p>
<hr>
<p th:text="${user.username}"></p>
<p th:text="${user.age}"></p>
<hr>
<div th:object="${user}">
<p th:text="*{username}"></p>
<p th:text="*{age}"></p>
</div>
</body>
</html>
//5. 링크 @{...} //
@GetMapping("/a5")
public String a5() {
return "main5";
}
//5. 링크 @{...} //
@GetMapping("/a55")
public String a55(String username, int age) {
System.out.println("/a55: "+username + "\t"+ age );
return "main5_1";
}
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<h1>main5.html</h1>
<a href="http://localhost:8085/app/a55?username=홍길동&age=30">이</a><br>
<a href="a55?username=홍길동&age=20">홍</a><br>
<a href="/app/a55?username=이순신&age=10">이</a><br>
<hr>
타임리프
<a th:href="@{http://localhost:8085/app/a55(username=홍길동, age=30)}">홍길동/30</a><br>
<a th:href="@{a55(username=세종, age=40)}">세종/40</a><br>
</body>
</html>
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<h1>main5_1.html</h1>
<p th:text="${param.username}"></p>
<p th:text="${param.age}"></p>
</body>
</html>
//6. 리터럴(literal): ${..}
@GetMapping("/a6")
public String a6(Model m) {
m.addAttribute("user", new User("홍길동", 20));
return "main6";
}
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<h1>main6.html 리터럴(literal: ${..})</h1>
<h3>1. 문자열 리터럴</h3>
<p th:text="'문자열을 넣기'">template file</p>
<h3>2. 숫자 리터럴</h3>
<p>this year is <span th:text="2013"></span> . </p>
<p>In two years, it will be <span th:text="2013+2">1234</span> .</p>
<h3>3. 불린 리터럴</h3>
<div th:if="${user.username}=='홍길동'">이름은 홍길동(thymeleaf가 처리)</div>
<div th:if="${user.username=='홍길동'}">이름은 홍길동(SpringEl이 처리)</div>
<div th:if="${user.username}!='홍길동'">이름은 홍길동(SpringEl가 처리)</div>
<div th:if="${user.getUsername()}!='aaa'">이름은 aaa 아님</div>
<hr>
<div th:if="${user.age}==20">나이는 20살(thymeleaf가 처리)</div>
<div th:if="${user.age}!=20">나이는 20살(thymeleaf가 처리)</div>
<div th:if="${user.age==20}">나이는 20살(SpringEl이 처리)</div>
<h3>4. null 리터럴</h3>
<div th:if="${user.username} != null">null 문자 사용 가능</div>
<div th:if="${user.username != null}">null 문자 사용 가능</div>
<h3>5. 텍스트 추가 및 리터럴 대채</h3>
<div th:text="'the name of ther user id ' + ${user.username}">아무개</div>
<div th:text="|the name of ther user id ${user.username} Hello |">리터럴 대체</div>
</body>
</html>
//7. 조건(if, 3항, switch) 및 반보
@GetMapping("/a7")
public String a7(Model m) {
m.addAttribute("user", new User("홍길동", 20));
m.addAttribute("user2", new User("Hong", 20));
List<User> list = Arrays.asList(new User("홍길동1",20),new User("홍길동2",30),new User("홍길동3",40));
m.addAttribute("userList", list);
return "main7";
}
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<style type="text/css">
.xxx{
color:red;
}
.yyy{
color:blue;
}
</style>
</head>
<body>
<h1>main7.html 조건 및 반복 ${...}</h1>
<h3>1. 조건 : th:if</h3>
<div th:if="${user.getAge()==20}"> user 나이 20살(springEl)</div>
<div th:if="${user.getAge()}==20"> user 나이 20살(thymeleaf)</div>
<h3>2. 3항 연산자 ?</h3>
<div th:class ="${user.getAge()==20}?'xxx':'yyy'" >Hello</div>
<div th:text ="${user.getAge()==20}?'20살임':'20살 아님'" >Hello</div>
<h3>3. switch ~ case ?</h3>
<div th:switch="${user2.username}">
<p th:case="'Hong'">hong2</p>
<p th:case="#{roles.manager}">manager</p>
<p th:case="*">default 역할</p>
</div>
<h3>4. 반복 : th:each, iterState</h3>
<table border="1">
<tr>
<td>이름</td><td>나이</td>
</tr>
<tr th:each="user : ${userList}">
<td th:text="${user.username}"></td>
<td th:text="${user.age}"></td>
</tr>
</table>
<h3>4. 반복 : th : each, iterState</h3>
<table border="1">
<tr>
<td>번호</td><td>이름</td><td>나이</td>
</tr>
<tr th:each="user, iterState : ${userList}">
<td th:text="${iterState.index} +' : ' + ${iterState.count}"></td>
<td th:text="${user.username}"></td>
<td th:text="${user.age}"></td>
</tr>
</table>
</body>
</html>
//8. 속성값 변경 및 static 파일 적용: th:attr
@GetMapping("/a8")
public String a8(Model m) {
m.addAttribute("user",new User("홍길동", 20));
m.addAttribute("imgWidth", 100);
m.addAttribute("imgHeight", 200);
m.addAttribute("xyz", "kkk2");
return "main8";
}
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<!-- <link rel="stylesheet" href="stu/css/style.css"> -->
<link rel="stylesheet" th:href="@{stu/css/style.css}">
<body>
<h1>main8.html 속성값 변경 및 static 파일 적용. th:attr</h1>
<img th:attr="src=@{/stu/images/a.jpg}, width=${imgWidth}, height=${imgHeight}" ><br>
<img th:src="@{/stu/images/a.jpg}" th:width="${imgWidth}" th:height="${imgHeight}" ><br>
<p th:class="${xyz}">hello</p>
<p th:attr="class=${xyz}">hello2</p>
아이디:<input type="text" name="userid" th:value="${user.username}"><br>
아이디:<input type="text" name="userid" th:attr="value = ${user.username}"><br>
<hr>
<form th:action="@{/a2}">
a2로 전송되는 id<input type="text" name="userid" th:value="${user.username}">
<input th:attr="type='submit', value='전송'">
</form>
</body>
</html>
//9.조각 모음 : th:fragment th:insert, th:replace
@RequestMapping("/a9")
public String a9(Model m) {
m.addAttribute("username", "홍길동");
return "main9";
}
main9.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<h1>조각모음 : th:fragment, th:insert, th:replace, th:include 권장안함</h1>
<h3>top포함 : th:insert</h3>
<div th:insert="fragments/top::menu"></div>
<h3>copy포함 : th:insert</h3>
<div th:insert="fragments/include::copy"></div>
<h3>copy변경: th:replace, 태그 자체가 교체됨(span태그가 div태그로 바뀜)</h3>
<span th:replace="fragments/include::xyz">안녕하세요</span>
</body>
</html>
include.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<div th:fragment="menu">
include.html fragment="menu" 로그인|회원가입 : <span th:text="${username}"></span>
</div>
<div th:fragment="copy">
include.htlm © 2011 The Good Thymes Virtual Grocery <span th:text="${username}"></span>
</div>
<div th:fragment="xyz">
include.htlm © 2011 The Good Thymes ............... <span th:text="${username}"></span>
</div>
</body>
</html>
top.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<div th:fragment="menu">
top.html fragment="menu" 로그인|회원가입 : <span th:text="${username}"></span>
</div>
</body>
</html>