SpringBoot使用JPA实现通用接口(增删查等)
title: SpringBoot使用JPA实现通用接口(增删查等)
date: 2019-08-16
author: maxzhao
tags:
- JAVA
- SpringBoot
- JPA
- Controller
- EntityManager
categories:
- SpringBoot
- JPA
- JAVA
一、前言
在我们的WEB
项目中,会写很多很多接口,对于增删改的接口来说,都大致相同。所以在我们的项目中就可以使用通用接口的形式实现增删改。
最终实现是以Entity
与 EntityManager
对数据库进行操作。
这里使用SpringBoot JPA
实现通用接口的 删除 功能。其它 Spring
等项目思路大致相同。
其它 :
我把实体类、SQL
、部分说明等放在了最后。
这里还要参考我的上一篇文章SpringBoot Jpa实体继承通用属性。
二、BaseController
实现
BaseController
是我们项目中实现通用接口的基础类。
Service
、Repository
都省略了接口类,测试的话自己写一下。
/**
* BaseController
* 基础的通用接口
*
* @author maxzhao
* @date 2019-08-15 10:33
*/
public class BaseController<T extends BaseEntity, ID> {
@Resource(name = "baseService")
private BaseService<T, ID> baseService;
/**
* 这里是为了让继承此类的接口类,能传入当前接口操作的实体,然后通过 Service 传入 repository
* 传入到 repository 之后 就可以使用 EntityManager 的通用方法了
*
* @param domainClass
*/
public void setDomainClass(Class<T> domainClass) {
baseService.setDomainClass(domainClass);
}
@ApiOperation(value = "/{id}", notes = "逻辑删除", response = ResultObj.class, httpMethod = "DELETE")
@DeleteMapping(value = "{id}")
@ResponseBody
public ResultObj<String> del(@PathVariable(value = "id") ID id) {
return baseService.del(id);
}
}
Service
@Slf4j
@Service(value = "baseService")
public class BaseServiceImpl<T extends BaseEntity, ID> implements BaseService<T, ID> {
@Autowired
private BaseRepository<T, ID> baseRepository;
/**
* 这里是 domainClass 的跳板
*
* @param domainClass
*/
@Override
public void setDomainClass(Class<T> domainClass) {
baseRepository.setDomainClass(domainClass);
}
@Override
public ResultObj<String> del(ID id) {
baseRepository.del(id);//这里到 repo 中模拟操作
return ResultObj.getDefaultResponse("删除成功");
}
}
Repository
/**
* BaseRepositoryImpl
*
* @author maxzhao
* @date 2019-08-15 11:11
*/
@Repository(value = "baseRepository")
@Transactional(readOnly = true)
public class BaseRepositoryImpl<T extends BaseEntity, ID> implements BaseRepository<T, ID> {
@PersistenceContext
private EntityManager entityManager;
/**
* 某个接口的实体类的类型
*/
private Class<T> domainClass;
@Override
public void setDomainClass(Class<T> domainClass) {
this.domainClass = domainClass;
}
@Override
public Boolean del(ID id) {
T entity = entityManager.find(domainClass, id);
return true;
}
}
至此,一个简单的、通用的删除接口就完成了。
删除是比较简单的,因为我做的项目一般都是逻辑删除,所有必须要自定义删除,而且想通用,就需要通用的实体属性,所以也就有了BaseEntity
。
BaseEntity
解读
这个类就是我前言中提到的通用实体属性的父类,这样就可以统一实体的通用属性,比如主键、逻辑删除状态、添加时间等。
@MappedSuperclass
实体继承映射注解要加载实体的父类上,比如如下代码:
/**
* BaseEntity
* 实体继承映射类基础,保存实体的通用属性
*
* @author maxzhao
* @date 2019-08-15 09:39
*/
@Data
@Accessors(chain = true)
@MappedSuperclass//实体继承映射
public class BaseEntity implements Serializable {
@Id
@Column(name = "ID")
@ApiModelProperty(value = "主键")
private Long id;
@Basic
@Column(name = "DEL_STATUS")
@ApiModelProperty(value = "状态 1启用 0 停用")
private Integer delStatus;
}
其它代码
接口
@Api(value = "应用接口日志")
@RestController
@RequestMapping("appLogApi")
public class AppLogApiController extends BaseController<AppLogApi, Long> {
@PostConstruct
public void PostConstruct() {
// 重点在这里,这是我能想出的比较简单的实现方法
super.setDomainClass(AppLogApi.class);
}
}
实体
/**
* 应用接口日志
*
* @author author
* @date 2019-7-23 15:38:57
*/
@Accessors(chain = true)
@Data
@Entity
@Table(name = "app_log_api", schema = "", catalog = "")
@ApiModel(value = "应用接口日志", description = "应用接口日志")
public class AppLogApi extends BaseEntity implements Serializable {
private static final long serialVersionUID = -1L;
@Basic
@Column(name = "API")
@ApiModelProperty(value = "请求地址")
private String api;
/******/
public AppLogApi() {
}
}
/**
* BaseEntity
* 实体集成映射类基础,保存实体的通用属性
*
* @author maxzhao
* @date 2019-08-15 09:39
*/
@Data
@Accessors(chain = true)
@MappedSuperclass//实体集成映射
public class BaseEntity implements Serializable {
@Id
@Column(name = "ID")
@ApiModelProperty(value = "主键")
private Long id;
@Basic
@Column(name = "DEL_STATUS")
@ApiModelProperty(value = "状态 1启用 0 停用")
private Integer delStatus;
}
create table gt_boot.app_log_api
(
id bigint(64) not null comment '主键'
primary key,
api varchar(100) null comment '请求地址',
del_status integer null
)
comment '应用接口日志';
@PostConstruct
解读
从Java EE5规范开始,Servlet中增加了两个影响Servlet生命周期的注解:
@PostConstruct
@PreDestroy
修饰一个非静态的void()
方法类似与init()
destory()
类似。写法有如下两种方式:
@PostConstruct
public void doA(){}
public @PostConstruct void doB(){}
加载顺序
[图片上传失败...(image-1b762b-1565938978247)]
与本文联系起来说
想要把实体AppLogApi.class
传参到BaseRepositoryImpl
中,就需要初始化bean
之后才可以调用bean
,但是@Autowired
注入是发生在A的构造方法执行完之后的。
所以要在生成对象时初始化AppLogApi.class
参数,就不能在构造函数中实现,这时候@PostContruct
的作用就体现出来了,@PostContruct
会在依赖注入完成后被自动调用。
Constructor > @Autowired > @PostConstruct