Spring Boot中引入Jpa和Thymeleaf
JPA是Java Persistence API的简称,中文名Java持久层API,是JDK 5.0注解或XML描述对象-关系表的映射关系,并将运行期的实体对象持久化到数据库中。
JPA展示如何将Plain Oriented Java Object(POJO)定义为entity,以及如何管理entity之间的关系。
Thymeleaf is a Java library. It is an XML/XHTML/HTML5 template engine able to apply a set of transformations to template files in order to display data and/or text produced by your applications.
简单说, Thymeleaf 是一个跟 Velocity、FreeMarker 类似的模板引擎,它可以完全替代 JSP
1、配置
pom.xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
application.properties
#模板编码
spring.thymeleaf.mode=LEGACYHTML5
#关闭thymeleaf缓存 开发时使用 否则没有实时画面
spring.thymeleaf.cache=false
如果配置LEGACYHTML5,则需要引入nekohtml
本次代码没有application.properties配置
<dependency>
<groupId>net.sourceforge.nekohtml</groupId>
<artifactId>nekohtml</artifactId>
</dependency>
MvcConfig.java定义CSS资源映射
@Configuration
public class MvcConfig implements WebMvcConfigurer{
/**
* 自定义资源映射
* addResoureHandler指的是对外暴露的访问路径
* addResourceLocations指的是文件放置的目录
*/
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/css/**").addResourceLocations("classpath:/css/");
}
/**
* 解决ie responsebody返回json的时候提示下载问题
*
* @return
*/
public MappingJackson2HttpMessageConverter customJackson2HttpMessageConverter() {
MappingJackson2HttpMessageConverter jsonConverter = new MappingJackson2HttpMessageConverter();
List<MediaType> supportedMediaTypes = new ArrayList<MediaType>();
MediaType media = new MediaType(MediaType.TEXT_HTML, Charset.forName("UTF-8"));
supportedMediaTypes.add(media);
jsonConverter.setSupportedMediaTypes(supportedMediaTypes);
return jsonConverter;
}
// @Override
// public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
// converters.add(customJackson2HttpMessageConverter());
// }
}
2、业务模拟
JpaUser.java
//实体类,利用对象关系映射生成数据库表
@Entity
@Table(name = "user_info")
public class JpaUser {
//javax.persistence.Id
@Id//如果引入org.springframework.data.annotation.Id,则启动报错
@GeneratedValue(strategy =GenerationType.SEQUENCE,generator="userid")
@SequenceGenerator(name="userid", sequenceName="SEQ_USER_INFO",allocationSize=1)
//sequenceName 是在oracle中创建的序列。allocationSize要指定为1,否则它会按照默认50个数字增长。
private Integer id;
private String name;
private String username;
private String password;
private String salt;
private String state;
set,get...
}
JpaUserRepository.java
package com.test.demo.jpa;
import org.springframework.data.repository.CrudRepository;
import com.test.demo.model.JpaUser;
/**
* 该接口会自动被实现,springdata默认实现了基本的增删改查 CRUD --> Create, Read, Update, Delete
*
* 1:Repository:最顶层的接口,是一个空的接口,目的是为了统一所有Repository的类型,且能让组件扫描的时候自动识别。
* 2:CrudRepository :是Repository的子接口,提供CRUD的功能
* 3:PagingAndSortingRepository:是CrudRepository的子接口,添加分页和排序的功能
* 4:JpaRepository:是PagingAndSortingRepository的子接口,增加了一些实用的功能,比如:批量操作等。
* 5:JpaSpecificationExecutor:用来做负责查询的接口
* 6:Specification:是Spring Data JPA提供的查询规范,要做复杂的查询,只需围绕这个规范来设置查询条件即可
*/
public interface JpaUserRepository extends CrudRepository<JpaUser, Long> {
}
JpaController.java
@Controller
public class JpaController {
@Autowired
// 自动从spring容器中加载userRepository
private JpaUserRepository userRepository;
@Resource
private PageModel pagemodel;
//@GetMapping是组合注解,是@RequestMapping(method = RequestMethod.GET)的缩写
@GetMapping(path = "/jpa/add")
public String addNewUser(@RequestParam String name,
@RequestParam String username, @RequestParam String password) {
// @RequestParam 表示接收的参数可以是get或post
JpaUser user = new JpaUser();
user.setName(name);
user.setUsername(username);
user.setPassword(password);
userRepository.save(user);
//重定向到 根目录index
return "redirect:/index";
}
@GetMapping(path = "/jpa/all")
public @ResponseBody Iterable<JpaUser> getAllUsers() {
// @ResponseBody 表示返回的string是一个回应(response),不是一个视图
// 返回一个json类型的user
return userRepository.findAll();
}
@RequestMapping({"/","/index"})
public String index(Model model, @RequestParam(value="pageNum",required=false) String pageNum){
if(pageNum==null){
pageNum="1";
}
int pagenum=Integer.parseInt(pageNum);
pagemodel.setPageNum(pagenum);
pagemodel.setTotalPages(2);
Iterable<JpaUser> users=userRepository.findAll();
model.addAttribute("users", users);
model.addAttribute("pagemodel",pagemodel);
return"/index";
}
}
PageModel.java
@Component
public class PageModel {
int pageNum;
int totalPages;
set,get...
}
3、测试
add执行后跳转index网页,add录入内容http://cos6743:8081/jpa/add?name=test&username=test001&password=test123
all录入内容http://cos6743:8081/jpa/all
静态文件路径
index.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8"/>
<title>用户列表-userList</title>
<link rel="stylesheet" th:href="@{css/bootstrap.css}"></link>
</head>
<body class="container">
<br/>
<h1>用户列表</h1>
<br/><br/>
<div class="with:80%">
<table class="table table-hover">
<thead>
<tr>
<th>#</th>
<th>账号</th>
<th>昵称</th>
<th>状态</th>
<th>密码</th>
<th>Edit</th>
<th>Delete</th>
</tr>
</thead>
<tbody>
<!--从controler层model set的对象,获取相关的内容;-->
<!--如果没有显示设置状态变量,thymeleaf会默认给个“变量名+Stat"的状态变量-->
<!--userStat是状态变量,有 index,count,size,current,even,odd,first,last等属性-->
<tr th:each="user,itemStat:${users}">
<th scope="row" th:text="${itemStat.count}">1</th>
<td th:text="${user.username}">neo</td>
<td th:text="${user.name}">neo</td>
<td th:text="${user.state}">6</td>
<td th:text="${user.password}">Otto</td>
<td><a th:href="@{/userInfo/edit(id=${user.id})}">edit</a></td>
<td><a th:href="@{/delete(id=${user.id})}">delete</a></td>
</tr>
</tbody>
</table>
<table class="table table-hover;with:50%" >
<tr>
<td><a th:href="@{/userInfo/page?pageNum=0}">首页</a></td>
<td th:switch="${pagemodel.pageNum}">
<p th:case="1"> <a th:href="@{/userInfo/page?pageNum=1}">上一页</a></p>
<p th:case="*"><a th:href="@{/userInfo/page(pageNum=${pagemodel.pageNum-1})}">上一页</a></p>
</td>
<td th:switch="${pagemodel.pageNum}">
<p th:case="${pagemodel.totalPages}"><a th:href="@{/userInfo/page(pageNum=${pagemodel.totalPages})}">下一页</a></p>
<p th:case="*"><a th:href="@{/userInfo/page(pageNum=${pagemodel.pageNum+1})}">下一页</a></p>
</td>
<td><a th:href="@{/userInfo/page(pageNum=${pagemodel.totalPages})}">尾页</a></td>
</tr>
</table>
</div>
<div class="form-group">
<div class="col-sm-2 control-label">
<a href="/userInfo/userAdd" th:href="@{/userInfo/userAdd}" class="btn btn-info">add</a>
</div>
</div>
</body>
</html>