springboot 利用JPA+Thymeleaf+Redis实现一个简单的案例
导入依赖:
缓存配置文件:resources/config/下 mycache.xml
<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="ehcache.xsd"> <!--timeToIdleSeconds 当缓存闲置n秒后销毁 --> <!--timeToLiveSeconds 当缓存存活n秒后销毁 --> <!-- 缓存配置
name:缓存名称。
maxElementsInMemory:缓存最大个数。
eternal:对象是否永久有效,一但设置了,timeout将不起作用。
timeToIdleSeconds:设置对象在失效前的允许闲置时间(单位:秒)。仅当eternal=false对象不是永久有效时使用,可选属性,默认值是0,也就是可闲置时间无穷大。
timeToLiveSeconds:设置对象在失效前允许存活时间(单位:秒)。最大时间介于创建时间和失效时间之间。仅当eternal=false对象不是永久有效时使用,默认是0.,也就是对象存活时间无穷大。
overflowToDisk:当内存中对象数量达到maxElementsInMemory时,Ehcache将会对象写到磁盘中。 diskSpoolBufferSizeMB:这个参数设置DiskStore(磁盘缓存)的缓存区大小。默认是30MB。每个Cache都应该有自己的一个缓冲区。
maxElementsOnDisk:硬盘最大缓存个数。
diskPersistent:是否缓存虚拟机重启期数据 Whether the disk
store persists between restarts of the Virtual Machine. The default value
is false.
diskExpiryThreadIntervalSeconds:磁盘失效线程运行时间间隔,默认是120秒。 memoryStoreEvictionPolicy:当达到maxElementsInMemory限制时,Ehcache将会根据指定的策略去清理内存。默认策略是
LRU(最近最少使用)。你可以设置为FIFO(先进先出)或是LFU(较少使用)。
clearOnFlush:内存数量最大时是否清除。 --> <!-- 磁盘缓存位置 -->
<!-- <diskStore path="java.io.tmpdir" /> --> <!-- 默认缓存 -->
<!-- <defaultCache
maxElementsInMemory="10000"
eternal="false"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
maxElementsOnDisk="10000000"
diskExpiryThreadIntervalSeconds="120"
memoryStoreEvictionPolicy="LRU">
<persistence strategy="localTempSwap" />
</defaultCache> -->
<!-- 测试 -->
<cache name="myCache"
eternal="false"
timeToIdleSeconds="2400"
timeToLiveSeconds="2400"
maxEntriesLocalHeap="10000"
maxEntriesLocalDisk="10000000"
diskExpiryThreadIntervalSeconds="120"
>
</cache>
</ehcache>
applicatin.yml:
server:
port: 80
servlet:
context-path: /
spring:
datasource:
username: root
password: root
url: jdbc:mysql:///boot_db?serverTimezone=UTC
jpa:
database: mysql
show-sql: true
hibernate:
ddl-auto: update
jackson:
date-format: yyyy-MM-dd HH:mm:ss
time-zone: Asia/Chongqing
redis:
host: localhost
port: 6379
cache:
ehcache:
config: classpath*:config/mycache.xml
type: redis
debug: true
主(启动)类:
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cache.annotation.EnableCaching;
@SpringBootApplication
@EnableCaching
public class ThymeleafDemoApplication {
public static void main(String[] args) {
SpringApplication.run(ThymeleafDemoApplication.class, args);
}
}
实体类:
@Entity
public class Student implements Serializable{
private static final long serialVersionUID = -6205110964034706733L;
private Integer id;
private String username;
private String password;
private Date birthday;
private Integer sex;
private String photo;
@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
public Integer getId() {
return id;
}
//省略 get set
Dao:
package com.shopping.repository;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import com.shopping.pojo.Student;
public interface StudentRepository extends JpaRepository<Student, Integer> {
/**
* 登录
* @param username
* @param password
* @return
*/
@Query(value = "select * from student where username = ?1 and password =?2",nativeQuery = true)
Student login(@Param("username")String username,@Param("password")String password);
/**
* 分页查询
* @param mohu
* @param pageable
* @return
*/
Page<Student> getListByUsernameContaining(String mohu,Pageable pageable);
}
业务类:
package com.shopping.service;
import javax.annotation.Resource;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Service;
import com.shopping.pojo.Student;
import com.shopping.repository.StudentRepository;
@Service
@CacheConfig(cacheNames = "myCache")
public class StudentService {
@Resource
private StudentRepository studentRepository;
@Cacheable
public Student login(String username, String password) {
System.err.println(".............cache login.................");
return this.studentRepository.login(username, password);
}
@CacheEvict(value = "students",allEntries = true)
public void flushList() {
}
@CachePut(key = "#p0.id")
public void save(Student student) {
System.err.println(".............cache add.................");
this.studentRepository.save(student);
}
@CachePut
public void update(Student student) {
// TODO Auto-generated method stub
System.err.println(".............cache update.................");
this.studentRepository.saveAndFlush(student);
}
@CacheEvict(key = "#p0")
public void delete(int id) {
System.err.println(".............cache delete.................");
Student stu=this.findById(id);
if(stu!=null) this.studentRepository.delete(stu);
}
@Cacheable(key = "#p0")
public Student findById(int id) {
System.err.println(".............cache findById.................");
return this.studentRepository.getOne(id);
}
@Cacheable(value = "students")
public Page<Student> list(PageRequest pageRequest, String mohu) {
return this.studentRepository.getListByUsernameContaining(mohu, pageRequest);
}
}
控制器:
package com.shopping.web;
import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import javax.annotation.Resource;
import javax.servlet.http.HttpSession;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
import com.shopping.pojo.Student;
import com.shopping.service.StudentService;
@Controller
public class StudentController {
@Resource
private StudentService studentService;
@RequestMapping("/")
public String tologin() {
return "login";
}
@PostMapping("/login")
public @ResponseBody boolean login(String username,String password,HttpSession session) {
Student stu=this.studentService.login(username, password);
if(stu!=null) {
session.setAttribute("logUser", stu);
return true;
}else {
return false;
}
}
@RequestMapping("/list")
public String list(Model model,@RequestParam(name="offset",defaultValue = "0")int offset,
@RequestParam(name="pagesize",defaultValue = "3")int pagesize,
@RequestParam(name="mohu",defaultValue = "",required = false)String mohu) {
PageRequest pageRequest=PageRequest.of(offset, pagesize);
Page<Student> pager= this.studentService.list(pageRequest,mohu);
model.addAttribute("pager", pager);
model.addAttribute("mohu", mohu);
return "list";
}
@RequestMapping("/add")
public String toadd() {
return "add";
}
@PostMapping("/add")
public String add(Student student,MultipartFile pic,Model model) throws IllegalStateException, IOException {
String path=System.getProperty("user.dir")+"\\src\\main\\resources\\static\\resources\\upload";
String new_name=new SimpleDateFormat("HHmmss").format(new Date())+pic.getOriginalFilename();
File file=new File(path+File.separator+new_name);
pic.transferTo(file);
student.setPhoto(new_name);
this.studentService.save(student);
this.studentService.flushList();
return "redirect:/list";
}
@RequestMapping("{id}/update")
public String toupdate(@PathVariable("id") int id,Model model) {
model.addAttribute("user", this.studentService.findById(id));
return "update";
}
@PostMapping("{id}/update")
public String update(Student student,MultipartFile pic,Model model) throws IllegalStateException, IOException {
String path=System.getProperty("user.dir")+"\\src\\main\\resources\\static\\resources\\upload";
String new_name=new SimpleDateFormat("HHmmss").format(new Date())+pic.getOriginalFilename();
File file=new File(path+File.separator+new_name);
pic.transferTo(file);
student.setPhoto(new_name);
this.studentService.update(student);
this.studentService.flushList();
return "redirect:/list";
}
@RequestMapping("/{id}/del")
@ResponseBody
public boolean delete(@PathVariable("id")int id) {
try {
this.studentService.delete(id);
this.studentService.flushList();
return true;
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
}
list.html:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>用户列表</title>
<script type="text/javascript" src="resources/js/jquery-2.0.3.js"></script>
<link rel="stylesheet" href="resources/css/bootstrap.min.css">
<script type="text/javascript">
$(function(){
$(".btn-default").click(function(){
location="list?offset="+$(this).val();
})
$(".btn-primary").click(function(){
location=$(this).val()+"/update";
})
$(".btn-warning").click(function(){
var id=$(this).val();
alert(id);
if(confirm("确认吗?")){
$.get(
id+"/del",
function(obj){
if(obj){
alert("ok");
location.reload();
}else{
alert("sorry");
}
}
)
}
})
})
</script>
</head>
<body>
<div class="container">
<div class="alert alert-success">
<h3>JPA + Thymeleaf 实现列表</h3>
欢迎<font color='blue'><span th:text="${session.logUser.username}"></span></font>登录
</div>
<br>
<form action="list">
<input type="text" name="mohu" th:value="${mohu}">
<input type="hidden" name="offset" th:value="${pager.number}">
<button class="btn btn-success" type="submit">模糊</button>
</form>
<table class="table table-bordered table-hover">
<tr>
<td>用户编号</td><td>账号</td><td>性别</td>
<td>生日</td><td>头像</td>
<td><button class="btn btn-success" onclick="javascript:location='add'">添加</button></td>
</tr>
<tr th:each="user,index:${pager.getContent()}">
<td th:text="${user.id}"></td>
<td th:text="${user.username}"></td>
<td th:text="${user.sex==0?'男':'女'}"></td>
<td th:text="${#dates.format(user.birthday,'yyyy-MM-dd')}"></td>
<td>
<img width="50px" height="50px" th:src="@{'resources/upload/'+${user.photo}}">
</td>
<td>
<button class="btn btn-warning" th:value="${user.id}">删除</button>
<button class="btn btn-primary" th:value="${user.id}">修改</button>
</td>
</tr>
<tr>
<td colspan="10" align="center">
共<span th:text="${pager.totalPages}"></span>页,
当前是<span th:text="${pager.number+1}"></span>页。
<button class="btn btn-default" th:value="0">首页</button>
<button class="btn btn-default" th:if="${not pager.isFirst()}" th:value="${pager.number-1}">上页</button>
<button class="btn btn-default" th:if="${not pager.isLast()}" th:value="${pager.number+1}">下页</button>
<button class="btn btn-default" th:value="${pager.totalPages-1}">末页</button>
</td>
</tr>
</table>
</div>
</body>
</html>