Spring全家桶实践-数据操作JPA
2019-08-02 本文已影响0人
一块自由的砖
知识贮备
Spring Data JPA官方网站
JPA规范与ORM框架之间的关系
Spring Data JPA与JPA规范的关系
Spring Data JPA中常用的注解
实践过程
目标:实现AOP日志记录到数据库中
数据用户权限设置,需要有创建表的权利,这里把库的权限都先给springsaas用户
grant all privileges on springsaas.* to springsaas@'10.1.60.%' identified by 'springsaas';
flush privileges;
引入依赖包
<!-- Spring Data JPA的相关依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<!-- 用于连接mysql的相关依赖 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!-- 数据库连接池(dbcp2),以后用阿里的druid相关依赖 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-dbcp2</artifactId>
</dependency>
配置application.properties 新增数据库,连接池,JPA配置
说明:
- com.mysql.jdbc.Driver已经废弃了,使用新的com.mysql.cj.jdbc.Driver
- spring.datasource.url username password 根据实际情况自行设置
- 连接池有很多,例如:c3p0,hikari,druid,dbcp2等等,本次使用的是dbcp2
#项目相关配置
server.port=8080
#服务名称
spring.application.name=springsaas
#数据库配置
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/springsaas?characterEncoding=UTF-8
spring.datasource.username=springsaas
spring.datasource.password=springsaas
##设置使用那个连接池
spring.datasource.type=org.apache.commons.dbcp2.BasicDataSource
#DBCP2配置(连接池)
##初始化连接池idle数量
spring.datasouece.dbcp2.initial-size=10
##连接最小idle数量
spring.datasource.dbcp2.min-idle=10
##连接最大idle数量
spring.datasource.dbcp2.max-idle=30
##连接超时的等待时间(30秒)
spring.datasource.dbcp2.max-wait-millis=30000
##轮询间隔时间,检测需要关闭的数据库连接 3分钟
spring.datasource.dbcp2.time-between-eviction-runs-millis=180000
#配置jpa
##配置数据库类型
spring.jpa.database=mysql
##配置是否输出sql语句
spring.jpa.show-sql=true
##ddl方式
#1、create:启动时删除上一次生成的表,并根据实体类生成表,表中数据会被清空。
#2、create-drop:启动时根据实体类生成表,sessionFactory关闭时表会被删除。
#3、update:启动时会根据实体类生成表,当实体类属性变动的时候,表结构也会更新,在初期开发阶段使用此选项。
#4、validate:启动时验证实体类和数据表是否一致,在我们数据结构稳定时采用此选项。
#5、none:不采取任何措施。
spring.jpa.hibernate.ddl-auto=update
#让控制器输出的json字符串格式更美观。
spring.jackson.serialization.indent-output=true
目录结构
logging目录结构实现源码
改造domain 实体类(bean)和数据表进行映射,并且配置好映射关系,粗浅的类比为pojo
package com.springboot.action.saas.common.logging.domain;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.hibernate.annotations.CreationTimestamp;
import javax.persistence.*;
import java.sql.Timestamp;
/*
* 日志数据和数据表实体类
* */
@Data
//jpa 实体
@Entity
//表名
@Table(name="mkt_log")
//lombok 注解,NoArgsConstructor 无参数构造函数
@NoArgsConstructor
public class Log {
//设置ID主键,定义生成策略为自增
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
//描述
private String description;
//方法名
private String method;
//参数,定义字段类型为text
@Column(columnDefinition = "text")
private String params;
//日志类型, 定义字段名称
@Column(name = "log_type")
private String logType;
//请求ip, 定义字段名称
@Column(name = "request_ip")
private String requestIp;
//请求耗时
private Long time;
//异常详细,定义字段名称
@Column(name = "exception_detail", columnDefinition = "text")
private String exceptionDetail;
//请求时间,实体插入数据库的时候设置这个数值
@CreationTimestamp
@Column(name = "create_time")
private Timestamp createTime;
//构造函数(代参)
public Log(String logType, Long time) {
this.logType = logType;
this.time = time;
}
}
新建Repository 接口来操作实体类对应的数据表,粗浅的理解为Dao
package com.springboot.action.saas.common.logging.repository;
import com.springboot.action.saas.common.logging.domain.Log;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.stereotype.Repository;
/*
* JpaRepository继承了接口PagingAndSortingRepository和QueryByExampleExecutor。
* PagingAndSortingRepository又继承CrudRepository。
* JpaRepository接口同时拥有基本CRUD功能以及分页功能。
* 官方的给的定义
* public interface JpaRepository<T, ID> extends PagingAndSortingRepository<T, ID>, QueryByExampleExecutor<T>
* T 实例类
* ID id的数据类型
* */
@Repository
public interface LogRepository extends JpaRepository<Log,Long> {
}
改造service impl,在上一个tag版本里面增加了记录数据库的功能
增加私有成员变量 logRepository
逻辑增加日志记录到数据库 logRepository.save(log);
package com.springboot.action.saas.common.logging.service.impl;
import com.springboot.action.saas.common.logging.domain.Log;
import com.springboot.action.saas.common.logging.repository.LogRepository;
import com.springboot.action.saas.common.logging.service.LogService;
import com.springboot.action.saas.common.utils.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
@Service
public class LogServiceImpl implements LogService {
//数据操作类,相当于DAO
@Autowired
private LogRepository logRepository;
/*
* 记录日志接口实现
**/
@Override
public void save(ProceedingJoinPoint joinPoint, Log log) {
//获取request 请求对象
HttpServletRequest request = ((ServletRequestAttributes)RequestContextHolder.getRequestAttributes())
.getRequest();
//getSignature获取切面相关信息,比如方法名、目标方法参数等信息
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
//获取抽象类(代理对象)方法
Method method = signature.getMethod();
//返回该元素的指定类型的注释,这里是Log注解
com.springboot.action.saas.common.logging.annotation.Log aopLog = method.getAnnotation(com.springboot.action.saas.common.logging.annotation.Log.class);
//获取注解传递的参数
if (log != null) {
log.setDescription(aopLog.value());
}
//通过最笨的反射方法,获取方法路径
String methodName = joinPoint.getTarget().getClass().getName()+"."+signature.getName()+"()";
log.setMethod(methodName);
//参数处理
//获取参数值
Object[] argValues = joinPoint.getArgs();
//获取参数名
String[] argNames = ((MethodSignature)joinPoint.getSignature()).getParameterNames();
//组织参数列表
String params = "{";
if(argValues != null){
for (int i = 0; i < argValues.length; i++) {
params += " " + argNames[i] + ": " + argValues[i];
}
}
log.setParams(params + " }");
//获取IP地址
log.setRequestIp(StringUtils.getIP(request));
//输出日志到控制台
System.out.println(log.toString());
//日志记录到数据库
logRepository.save(log);
}
}
运行测试效果
控制台输出sql,启动会创建表
Using dialect: org.hibernate.dialect.MySQL5Dialect
Hibernate: create table mkt_log (id bigint not null auto_increment, create_time datetime, description varchar(255), exception_detail text, log_type varchar(255), method varchar(255), params text, request_ip varchar(255), time bigint, primary key (id)) engine=MyISAM
数据库springsaas会创建mkt_log,当有自定义@Log注解的接口被访问请求后,表就会插入一条数据。
打标签
打tag 1.0.5版本,提交代码。
git tag -a v1.0.5 -m "实现日志信息通过JPA记录到数据库"
git push origin v1.0.5