java使用内嵌Tomcat开发javaWeb项目
写在前面
这一篇博客,是在java篇-(java使用内嵌Tomcat开发javaWeb项目-中级篇)这篇博客之上进行扩展,整合spring data jpa,junit,thymeleaf,redis实现使用此方式开发项目
项目初始结构请查看java篇-(java使用内嵌Tomcat开发javaWeb项目-中级篇
这篇博客,博客地址: java篇-(java使用内嵌Tomcat开发javaWeb项目-中级篇)
整合spring data jpa
pom.xml添加spring data jpa相关依赖
这里只复制了jpa相关部分pom文件内容
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<kotlin.code.style>official</kotlin.code.style>
<kotlin.compiler.jvmTarget>11</kotlin.compiler.jvmTarget>
<tomcat.embed.version>9.0.31</tomcat.embed.version>
<thymeleaf.version>3.0.12.RELEASE</thymeleaf.version>
<spring.version>5.3.5</spring.version>
<fastjson.version>1.2.73</fastjson.version>
<validation-api.version>2.0.1.Final</validation-api.version>
<hibernate-validator.version>6.2.0.Final</hibernate-validator.version>
<javax.el-api.version>3.0.0</javax.el-api.version>
<slf4j.version>1.7.30</slf4j.version>
<log4j2.version>2.14.1</log4j2.version>
<spring.data.version>2.4.7</spring.data.version>
<hikaricp.version>4.0.3</hikaricp.version>
<hibernate.version>5.4.15.Final</hibernate.version>
<hibernate.jpa.version>1.0.2.Final</hibernate.jpa.version>
<javax.persistence-api.version>2.2</javax.persistence-api.version>
<mysql.version>8.0.23</mysql.version>
</properties>
<dependencies>
<dependency>
<groupId>javax.persistence</groupId>
<artifactId>javax.persistence-api</artifactId>
<version>${javax.persistence-api.version}</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>${hibernate.version}</version>
</dependency>
<dependency>
<groupId>org.hibernate.javax.persistence</groupId>
<artifactId>hibernate-jpa-2.1-api</artifactId>
<version>${hibernate.jpa.version}</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.zaxxer/HikariCP -->
<dependency>
<groupId>com.zaxxer</groupId>
<artifactId>HikariCP</artifactId>
<version>${hikaricp.version}</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql.version}</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework.data/spring-data-jpa -->
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa</artifactId>
<version>${spring.data.version}</version>
</dependency>
...
添加spring data jpa相关配置
在resources目录下面创建spring-config.xml,用来加载配置文件
在spring-config.xml里面配置加载配置文件
spring-config.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
<context:property-placeholder location="classpath:db.properties" />
</beans>
创建数据库配置文件
db.properties
db.username=root
db.password=123456
db.driverClassName=com.mysql.cj.jdbc.Driver
db.url=jdbc:mysql://192.168.101.150:3306/embed-tomcat?allowPublicKeyRetrieval=true&characterEncoding=utf-8&useSSL=false&serverTimezone=GMT%2B8&useUnicode=true
db.maxSize=5
db.maxLifetime=300000
db.minIdle=1
在resources目录下面创建spring-jpa.xml,用来存放jpa相关配置
在spring-jpa.xml添加jpa相关配置
spring-jpa.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jpa="http://www.springframework.org/schema/data/jpa"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/data/jpa https://www.springframework.org/schema/data/jpa/spring-jpa.xsd">
<!-- 扫描jpa repository 接口 -->
<jpa:repositories base-package="com.lhstack.embed.repository" entity-manager-factory-ref="entityManagerFactoryBean"
transaction-manager-ref="transactionManager"/>
<!-- 开启事物注解驱动 -->
<tx:annotation-driven transaction-manager="transactionManager"/>
<bean id="dataSource" class="com.zaxxer.hikari.HikariDataSource">
<property name="username" value="${db.username}"/>
<property name="password" value="${db.password}"/>
<property name="jdbcUrl" value="${db.url}"/>
<property name="driverClassName" value="${db.driverClassName}"/>
<property name="minimumIdle" value="${db.minIdle}"/>
<property name="maximumPoolSize" value="${db.maxSize}"/>
<!-- 单个链接的最大生命周期 -->
<property name="maxLifetime" value="${db.maxLifetime}"/>
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="dataSource" ref="dataSource"/>
<property name="entityManagerFactory" ref="entityManagerFactoryBean"/>
</bean>
<bean id="entityManagerFactoryBean" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="jpaProperties">
<props>
<!-- 格式化jpa打印的sql语句 -->
<prop key="hibernate.format_sql">true</prop>
</props>
</property>
<!-- 扫描jpa entity所在包里面的类,与数据库表进行绑定 -->
<property name="packagesToScan" value="com.lhstack.embed.entity.domain"/>
<property name="jpaVendorAdapter" ref="jpaVendorAdapter"/>
</bean>
<bean id="jpaVendorAdapter" class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<!-- 根据entity自动生成数据库表,同步 -->
<property name="generateDdl" value="true"/>
<property name="database" value="MYSQL"/>
<!-- 显示sql -->
<property name="showSql" value="true"/>
</bean>
</beans>
创建entity
这里包就是上面jpa配置里面的entityManagerFactoryBean.packagesToScan所在的包
User.java
package com.lhstack.embed.entity.domain;
import javax.persistence.*;
import java.util.Date;
/**
* @author lhstack
* Entity 标识此对象是数据库里面的表
* Table标识对应数据库那张表,这里对应的就是t_user这张表
*/
@Entity
@Table(name = "t_user")
public class User {
/**
* Id标识此字段为主键
* GenerationType.IDENTITY是设置id自增
*/
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
@Column(name = "name",length = 20,nullable = false,unique = true)
private String name;
@Column(name = "username",length = 20,nullable = false,unique = true)
private String username;
@Column(name = "password",length = 200,nullable = false)
private String password;
@Column(name = "create_time",nullable = false)
private Date createTime;
@Column(name = "update_time",nullable = false)
private Date updateTime;
public User() {
}
public User(Integer id, String name, String username, String password, Date createTime, Date updateTime) {
this.id = id;
this.name = name;
this.username = username;
this.password = password;
this.createTime = createTime;
this.updateTime = updateTime;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public Date getCreateTime() {
return createTime;
}
public void setCreateTime(Date createTime) {
this.createTime = createTime;
}
public Date getUpdateTime() {
return updateTime;
}
public void setUpdateTime(Date updateTime) {
this.updateTime = updateTime;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", name='" + name + '\'' +
", username='" + username + '\'' +
", password='" + password + '\'' +
", createTime=" + createTime +
", updateTime=" + updateTime +
'}';
}
}
创建对应的repository
同理,这里对应jpa:repositories标签里面的base-package属性值
UserRepository.java
package com.lhstack.embed.repository;
import com.lhstack.embed.entity.domain.User;
import org.springframework.data.jpa.repository.JpaRepository;
public interface UserRepository extends JpaRepository<User,Integer> {
}
在resources目录下面创建spring-service.xml配置文件,配置扫描service相关接口
spring-service.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="com.lhstack.embed.service" />
</beans>
在配置的包下面创建对应的service接口和实现类
IUserService.java
package com.lhstack.embed.service;
import com.lhstack.embed.entity.domain.User;
import org.springframework.data.domain.Page;
import java.util.List;
/**
* 用户相关接口
* @author lhstack
*/
public interface IUserService {
User save(User user);
User update(Integer id,User user);
List<User> queryList();
Page<User> queryPageList(Integer page,Integer size);
User findById(Integer id);
void deleteById(Integer id);
}
UserServiceImpl.java
package com.lhstack.embed.service.impl;
import com.lhstack.embed.entity.domain.User;
import com.lhstack.embed.repository.UserRepository;
import com.lhstack.embed.service.IUserService;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import java.util.Date;
import java.util.List;
import java.util.Optional;
/**
* @author lhstack
* 用户操作相关实现类
*/
@Service
public class UserServiceImpl implements IUserService {
private final UserRepository userRepository;
public UserServiceImpl(UserRepository userRepository) {
this.userRepository = userRepository;
}
@Override
@Transactional(readOnly = false, propagation = Propagation.REQUIRED, rollbackFor = {Exception.class, RuntimeException.class})
public User save(User user) {
user.setCreateTime(new Date());
user.setUpdateTime(new Date());
return userRepository.save(user);
}
@Override
@Transactional(readOnly = false, propagation = Propagation.REQUIRED, rollbackFor = {Exception.class, RuntimeException.class})
public User update(Integer id, User user) {
Optional<User> optionalUser = userRepository.findById(id);
if (optionalUser.isPresent()) {
User result = optionalUser.get();
if (StringUtils.hasText(user.getName())) {
result.setName(user.getName());
}
if (StringUtils.hasText(user.getUsername())) {
result.setUsername(user.getUsername());
}
if (StringUtils.hasText(user.getPassword())) {
result.setPassword(user.getPassword());
}
result.setUpdateTime(new Date());
return userRepository.save(result);
}
return null;
}
@Override
@Transactional(readOnly = true, propagation = Propagation.SUPPORTS)
public List<User> queryList() {
return userRepository.findAll();
}
@Override
@Transactional(readOnly = true, propagation = Propagation.SUPPORTS)
public Page<User> queryPageList(Integer page, Integer size) {
return userRepository.findAll(PageRequest.of(page - 1, size));
}
@Override
@Transactional(readOnly = true, propagation = Propagation.SUPPORTS)
public User findById(Integer id) {
return userRepository.findById(id).orElseGet(null);
}
@Override
@Transactional(readOnly = false, propagation = Propagation.REQUIRED, rollbackFor = {Exception.class, RuntimeException.class})
public void deleteById(Integer id) {
userRepository.deleteById(id);
}
}
创建UserController,暴露curd接口
UserController.java
package com.lhstack.embed.controller;
import com.lhstack.embed.entity.domain.User;
import com.lhstack.embed.service.IUserService;
import org.springframework.data.domain.Page;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("user")
public class UserController {
private final IUserService userService;
public UserController(IUserService userService) {
this.userService = userService;
}
@PostMapping
public User save(@RequestBody User user) {
return userService.save(user);
}
@PutMapping("{id}")
public User updateById(@PathVariable("id") Integer id, @RequestBody User user) {
return userService.update(id, user);
}
@GetMapping("list")
public List<User> queryList(){
return userService.queryList();
}
@GetMapping("page")
public Page<User> queryPageList(@RequestParam(name = "page",defaultValue = "1")Integer page,
@RequestParam(name = "size",defaultValue = "10") Integer size){
return userService.queryPageList(page,size);
}
@DeleteMapping("{id}")
public ResponseEntity<Boolean> deleteById(@PathVariable("id") Integer id){
userService.deleteById(id);
return ResponseEntity.ok(true);
}
}
启动项目
控制台打印了对应的sql,数据库自动创建了对应的表结构
使用postman测试接口
添加数据
更新数据
查询数据
分页查询
整合junit,实现单元测试
pom.xml添加junit相关依赖
这里只复制junit相关的内容
pom.xml
...
<junit.version>4.12</junit.version>
</properties>
<dependencies>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-test -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
...
创建test类,配置spring使用junit进行单元测试
执行单元测试
整合thymeleaf,实现mvc架构
在pom.xml添加thymeleaf相关依赖
由于之前在pom.xml里面预留了thymeleaf的依赖,所以这里添加thymeleaf集成spring的依赖即可
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf-spring5</artifactId>
<version>${thymeleaf.version}</version>
</dependency>
在resources目录创建spring-thymeleaf.xml文件
用于存放spring继承thymeleaf的配置信息
spring-thymeleaf.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd">
<bean id="springResourceTemplateResolver"
class="org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver">
<!-- 开启缓存,并配置缓存时间 -->
<property name="cacheTTLMs" value="60000"/>
<property name="cacheable" value="true"/>
<!-- 配置前缀,这里会根据tomcat的docBase作为相对路径向下匹配 -->
<property name="prefix" value="/templates/"/>
<!-- 后缀,这里根据controller返回的字符串,拼接为context.getRealPath() + prefix + controller return value + suffix -->
<property name="suffix" value=".html"/>
<property name="characterEncoding" value="UTF-8"/>
<property name="templateMode" value="HTML5"/>
</bean>
<bean id="templateEngine" class="org.thymeleaf.spring5.SpringTemplateEngine">
<property name="templateResolver" ref="springResourceTemplateResolver"/>
<!-- 配置支持spring el表达式 -->
<property name="enableSpringELCompiler" value="true"/>
</bean>
<bean class="org.thymeleaf.spring5.view.ThymeleafViewResolver" id="viewResolver">
<property name="characterEncoding" value="UTF-8"/>
<property name="templateEngine" ref="templateEngine"/>
<!-- 设置响应给浏览器的内容格式 -->
<property name="contentType" value="text/html;charset=utf-8"/>
</bean>
<!-- 配置视图解析器 -->
<mvc:view-resolvers>
<ref bean="viewResolver"/>
</mvc:view-resolvers>
</beans>
编写controller进行测试
IndexController.kt
package com.lhstack.embed.controller
import org.springframework.stereotype.Controller
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.RequestMapping
@Controller
@RequestMapping("index")
class IndexController {
@GetMapping
fun index():String{
return "index"
}
}
在resources目录下面创建对应的html页面
启动项目,访问index
结合spring data jpa,实现简单的crud
修改IndexController,添加crud相关逻辑
IndexController.kt
package com.lhstack.embed.controller
import com.lhstack.embed.entity.domain.User
import com.lhstack.embed.service.IUserService
import org.springframework.stereotype.Controller
import org.springframework.ui.Model
import org.springframework.web.bind.annotation.*
import java.util.*
@Controller
@RequestMapping("thymeleaf")
class IndexController(private val userService: IUserService) {
@GetMapping("index")
fun index(model: Model,
@RequestParam(name = "page",defaultValue = "1") page: Int,
@RequestParam(name = "size",defaultValue = "10")size: Int
):String{
model.addAttribute("list",this.userService.queryPageList(page,size))
return "index"
}
/**
* 跳转更新页面
*/
@GetMapping("toUpdatePage/{id}")
fun toUpdatePage(model:Model,@PathVariable("id") id:Int):String{
val user = this.userService.findById(id)
if(Objects.isNull(user)){
return "redirect:/thymeleaf/index"
}
model.addAttribute("user",user)
return "update"
}
@PostMapping("update/{id}")
fun update(user:User,@PathVariable("id") id:Int):String{
this.userService.update(id,user)
return "redirect:/thymeleaf/index"
}
/**
* 跳转保存页面
*/
@GetMapping("toSave")
fun toSavePage():String{
return "save"
}
@PostMapping("save")
fun save(user:User):String{
this.userService.save(user)
return "redirect:/thymeleaf/index"
}
@GetMapping("del/{id}")
fun delete(@PathVariable("id") id:Int):String{
this.userService.deleteById(id)
return "redirect:/thymeleaf/index"
}
}
修改index.html,实现渲染用户列表
index.html
<!DOCTYPE html>
<html lang="en" xmlns:th="https://www.thymeleaf.org/">
<head>
<meta charset="UTF-8">
<title>index</title>
</head>
<body>
<a th:href="${#request.contextPath} + '/thymeleaf/toSave'">新增</a>
<table>
<thead>
<tr>
<th>id</th>
<th>名称</th>
<th>用户名</th>
<th>密码</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<tr th:each="item,stat : ${list}">
<td th:text="${item.id}"></td>
<td th:text="${item.name}"></td>
<td th:text="${item.username}"></td>
<td th:text="${item.password}"></td>
<td>
<a th:href="${#request.getContextPath()} + '/thymeleaf/toUpdatePage/' + ${item.id}">更新</a>
<a th:href="${#request.getContextPath()} + '/thymeleaf/del/' + ${item.id}">删除</a>
</td>
</tr>
</tbody>
</table>
<a th:href="${#request.getContextPath()} + '/thymeleaf/index?page=1&size=' + ${list.pageable.pageSize}">首页</a>
<a th:href="${#request.getContextPath()} + '/thymeleaf/index?page=' + ${list.pageable.pageNumber <= 0 ? 1 : list.pageable.pageNumber} + '&size=' + ${list.pageable.pageSize}">上一页</a>
<a th:href="${#request.getContextPath()} + '/thymeleaf/index?page=' + ${list.pageable.pageNumber + 2} + '&size=' + ${list.pageable.pageSize}">下一页</a>
</body>
</html>
添加新增页面,实现数据的新增
save.html
<!DOCTYPE html>
<html lang="en" xmlns:th="https://www.thymeleaf.org/">
<head>
<meta charset="UTF-8">
<title>update</title>
</head>
<body>
<form th:action="${#request.contextPath} + '/thymeleaf/save/'" method="post">
<div>
<label for="name">名称</label>
<input name="name" id="name"/>
</div>
<div>
<label for="username">用户名</label>
<input name="username" id="username" />
</div>
<div>
<label for="password">密码</label>
<input name="password" id="password" />
</div>
<div>
<input type="submit" value="提交" /><input type="reset" value="重置" />
</div>
</form>
</body>
</html>
添加更新页面,实现数据更新
update.html
<!DOCTYPE html>
<html lang="en" xmlns:th="https://www.thymeleaf.org/">
<head>
<meta charset="UTF-8">
<title>update</title>
</head>
<body>
<form th:action="${#request.contextPath} + '/thymeleaf/update/' + ${user.id}" method="post">
<div>
<label for="name">名称</label>
<input name="name" id="name" th:value="${user.name}" />
</div>
<div>
<label for="username">用户名</label>
<input name="username" id="username" th:value="${user.username}" />
</div>
<div>
<label for="password">密码</label>
<input name="password" id="password" th:value="${user.password}" />
</div>
<div>
<input type="submit" value="提交" /><input type="reset" value="重置" />
</div>
</form>
</body>
</html>
启动项目
访问首页
新增数据
修改数据
删除数据
添加redis,实现数据的缓存
pom.xml添加spring-data-redis和redis客户端相关依赖
...
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<kotlin.code.style>official</kotlin.code.style>
<kotlin.compiler.jvmTarget>11</kotlin.compiler.jvmTarget>
<tomcat.embed.version>9.0.31</tomcat.embed.version>
<thymeleaf.version>3.0.12.RELEASE</thymeleaf.version>
<spring.version>5.3.5</spring.version>
<fastjson.version>1.2.73</fastjson.version>
<validation-api.version>2.0.1.Final</validation-api.version>
<hibernate-validator.version>6.2.0.Final</hibernate-validator.version>
<javax.el-api.version>3.0.0</javax.el-api.version>
<slf4j.version>1.7.30</slf4j.version>
<log4j2.version>2.14.1</log4j2.version>
<spring.data.version>2.4.7</spring.data.version>
<hikaricp.version>4.0.3</hikaricp.version>
<hibernate.version>5.4.15.Final</hibernate.version>
<hibernate.jpa.version>1.0.2.Final</hibernate.jpa.version>
<javax.persistence-api.version>2.2</javax.persistence-api.version>
<mysql.version>8.0.23</mysql.version>
<junit.version>4.12</junit.version>
<lettuct.version>6.1.0.RELEASE</lettuct.version>
</properties>
<dependencies>
<!-- https://mvnrepository.com/artifact/io.lettuce/lettuce-core -->
<dependency>
<groupId>io.lettuce</groupId>
<artifactId>lettuce-core</artifactId>
<version>${lettuct.version}</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework.data/spring-data-redis -->
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-redis</artifactId>
<version>${spring.data.version}</version>
</dependency>
...
修改spring-config.xml,加载redis配置文件
redis.propertis
redis.properties
redis.database=0
redis.host=192.168.101.150
redis.port=6379
resources目录下创建spring-redis.xml配置文件
spring-redis.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:cache="http://www.springframework.org/schema/cache"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache.xsd">
<bean id="redisConnectionFactory"
class="org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory">
<constructor-arg index="0" ref="standaloneConfiguration"/>
</bean>
<bean id="standaloneConfiguration" class="org.springframework.data.redis.connection.RedisStandaloneConfiguration">
<property name="database" value="${redis.database}"/>
<property name="port" value="${redis.port}"/>
<property name="hostName" value="${redis.host}"/>
</bean>
<bean id="cacheManager" class="org.springframework.data.redis.cache.RedisCacheManager" factory-method="create">
<constructor-arg ref="redisConnectionFactory"/>
</bean>
<!-- 后续可能会用到调redis api的地方 ,这里先创建出redisTemplate -->
<bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate">
<property name="connectionFactory" ref="redisConnectionFactory"/>
</bean>
<!-- 开启缓存,并使用redis作为cache组件 -->
<cache:annotation-driven cache-manager="cacheManager"/>
</beans>
修改UserServiceImpl里面的方法,加入缓存功能
UserServiceImpl.java
package com.lhstack.embed.service.impl;
import com.lhstack.embed.entity.domain.User;
import com.lhstack.embed.repository.UserRepository;
import com.lhstack.embed.service.IUserService;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import java.util.Date;
import java.util.List;
import java.util.Optional;
/**
* @author lhstack
* 用户操作相关实现类
*/
@Service
public class UserServiceImpl implements IUserService {
private final UserRepository userRepository;
public UserServiceImpl(UserRepository userRepository) {
this.userRepository = userRepository;
}
/**
* @CacheEvict(cacheNames = "user",allEntries = true)清除cacheName为user的所有缓存
* @param user
* @return
*/
@Override
@Transactional(readOnly = false, propagation = Propagation.REQUIRED, rollbackFor = {Exception.class, RuntimeException.class})
@CacheEvict(cacheNames = "user",allEntries = true)
public User save(User user) {
user.setCreateTime(new Date());
user.setUpdateTime(new Date());
return userRepository.save(user);
}
@CacheEvict(cacheNames = "user",allEntries = true)
@Override
@Transactional(readOnly = false, propagation = Propagation.REQUIRED, rollbackFor = {Exception.class, RuntimeException.class})
public User update(Integer id, User user) {
Optional<User> optionalUser = userRepository.findById(id);
if (optionalUser.isPresent()) {
User result = optionalUser.get();
if (StringUtils.hasText(user.getName())) {
result.setName(user.getName());
}
if (StringUtils.hasText(user.getUsername())) {
result.setUsername(user.getUsername());
}
if (StringUtils.hasText(user.getPassword())) {
result.setPassword(user.getPassword());
}
result.setUpdateTime(new Date());
return userRepository.save(result);
}
return null;
}
@Cacheable(cacheNames = "user",key = "'queryList'")
@Override
@Transactional(readOnly = true, propagation = Propagation.SUPPORTS)
public List<User> queryList() {
return userRepository.findAll();
}
@Override
@Transactional(readOnly = true, propagation = Propagation.SUPPORTS)
@Cacheable(cacheNames = "user",key = "'queryPageList page:::' + #p0 + ' size:::' + #p1")
public Page<User> queryPageList(Integer page, Integer size) {
return userRepository.findAll(PageRequest.of(page - 1, size));
}
@Override
@Transactional(readOnly = true, propagation = Propagation.SUPPORTS)
@Cacheable(cacheNames = "user",key = "'findById id:::' + #p0")
public User findById(Integer id) {
return userRepository.findById(id).orElseGet(null);
}
@Override
@Transactional(readOnly = false, propagation = Propagation.REQUIRED, rollbackFor = {Exception.class, RuntimeException.class})
@CacheEvict(cacheNames = "user",allEntries = true)
public void deleteById(Integer id) {
userRepository.deleteById(id);
}
}
修改User.java类,让其实现Serializable接口,保证此对象可以被序列化
启动项目
第一次请求,控制台打印出了sql
第二次请求,还是第一次请求的sql,说明这一次没有走数据库
查看redis,缓存已经进来了
添加数据,控制台走了两次sql,第一次是插入数据,第二次是重定向到index时,查询数据,说明缓存是成功更新了的