SpringBoot / DB연동, JPA, MVC, ajax, Thymeleaf

Cheol·2023년 8월 23일
1
post-thumbnail

👍PreparedStatement 연동

Edit Starter

  • JDBC API
  • Spring Data JDBC
  • Oracle Driver

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;
	}
}

DB연동 아키텍쳐


❗JPA??

JPA는 자바 진영에서 ORM(Object-Relational-Mapping) 기술 표준으로 사용되는 인터페이스의 모음이다.
실제적으로 구현된 것이 아닌, 구현된 클래스들과 매핑을 해주기 위해 사용되는 프레임워크이다.
대표적 오픈소스는 Hibernate를 사용한다.

❔ORM : application classRDB(Relational Database)의 테이블을 매핑(연결)한다는 뜻이며,

application의 객체를 RDB테이블에 자동으로 영속화 해주는 것이라고 보면된다.

  • 장점
    • SQL문이 아니고 Method를 통해 DB를 조작할 수 있어서, 개발자가 객체 모델을 이용하여 비즈니스 로직을 구성하는 데만 집중할 수 있다.
    • Query와 같이 필요한 선언문, 할당 등의 부수적인 코드가 줄어들어, 각종 객체에 대한 코드를 별도로 작성하여 코드의 가독성을 높인다.
    • 오직 객체지향적 접근만 고려하면 되기 떄문에 생산성이 증가한다.
    • 매핑하는 정보가 Class로 명시 되었기 때문에 ERD를 보는 의존도를 낮출 수 있다.
    • 따라서 유지보수 및 리팩토링에 유리하다.
    • MySQL에서 Oracle로 변환한다고 하면 새로 쿼리를 짜야하는 경우가 생기는데, ORM을 사용하면 쿼리를 수정할 필요가 없다.

  • 단점
    • 프로젝트 규모가 크고 복잡하여 설계가 잘못된 경우, 속도 저하 및 일관성을 무너뜨리는 문제점이 생길 수 있다.
    • 복잡하고 무거운 Query는 속도를 위해 별도의 튜닝이 필요하기 때문에 결국 SQL문을 써야한다.
    • 학습 비용이 비싸다.

JPA(Java Persistence API)

JPA를 사용하는 이유는 반복적인 CRUD SQL을 처리해주기 때문이다.
따라서 SQL이 아닌 객체 중심으로 개발할 수 있다는 것이고, 이는 결국 생산성이 좋아지고 유지보스가 수월해진다.

JPA는 패러다임의 불일치도 해결하였다.
-> Java는 상속관계(부모클래스와 자식클래스의 관계) 가 존재하는데 DB에서는 이런 객체의 상속관계를 지원하지 않는다. 이런 상속관계를 JPA는 Table 슈퍼타입 서브타입 관계 방식으로 해결하였고, 연관관계를 테이블 연관관계 방식으로 해결하였다.

추가적으로 알아둬야 할 것은, 스프링에서 흔히 사용하는 것으로 알고있는 JPA는, JPA를 이용하는 spring-data-jpa 프레임워크이지 JPA는 아니다.

-출처: 자바 ORM 표준 JPA 프로그래밍 / 저자: 김영한 -


JPA_h2

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 성공.


JPA_Oracle

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

Mybatis 연동

SpringBoot MVC

  • 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-propertiesspring.mvc.static-path-pattern=/resources/* 를 써줘야함)


JSP_mybatis

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

메서드 레벨에 @ResponseBody가 부여되면 그 메서드가 리턴하는 객체는 뷰를 통해 결과를 만들어내는 모델로 사용되는 대신, 메시지 컨버터를 통해 바로 HTTP응답의 메시지 본문으로 전환된다.

근본적으로 @RequestBody@ResponseBodyXML이나 JSON과 같은 메시지 기반의 커뮤니케이션을 위해 사용된다.

@RequestMapping(/hello”)
@ResponseBody
public String hello(){
return<html><body>Hello</body></html>);
}

--> 이 코드에서 @ResponseBody가 없다면 String 타입의 리턴값은 뷰 이름으로 인식된다. 그러나 있기 때문에 HttpServletResponse의 출력 스트림으로 동작한다.

Spring에서는 @RequestBody,@ResponseBody를 사용하기 위해 Jackson 라이브러리가 필요했으나 SpringBoot에서는 자동으로 내장되어있어 필요없다.



  • 예제

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>

@PathVariable

파라미터화 된 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>

@RestController

@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>



Thymeleaf

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>



Thymeleaf 사용법

바인딩 - ${...}

I18N - #{...}

//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>

리터럴(literal) : ${..}

	//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>

조건(if,3항) 및 반복(each, switch)

	//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 &copy; 2011 The Good Thymes Virtual Grocery <span th:text="${username}"></span>
</div>

<div th:fragment="xyz">
    include.htlm &copy; 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>

0개의 댓글