Java持久层和控制器的封装

spring-boot-maven-plugin

在application.properties文件中配置数据库的链接。

spring.datasource.url=jdbc:mysql://localhost:3306/springbootdemo?serverTimezone=GMT%2B8

spring.datasource.username=root

spring.datasource.password=root

spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

spring.jpa.database-platform=org.hibernate.dialect.MySQL5InnoDBDialect

spring.jpa.show-sql=true

spring.jpa.hibernate.ddl-auto=update

spring.jpa.hibernate.use-new-id-generator-mappings=false

spring.servlet.multipart.max-request-size=2048MB

spring.servlet.multipart.max-file-size=2048MB

server.port=8080

在写代码之前,我们先来看一下项目的目录结构。

代码实现

对持久层的封装,我们首先需要确定的就是找到对应的实体类,之后才能对其进行操作,可以通过反射机制找到当前的实体类。

新建一个反射工具类GenericsUtils,这个类很重要,可以帮助我们找到对应的实体类。

import java.lang.reflect.ParameterizedType;

import java.lang.reflect.Type;

public class GenericsUtils {

/**

  • 通过反射,获得定义Class时声明的父类的范型参数的类型. 如public BookManager extends

  • GenricManager

  • @param clazz The class to introspect

  • @return the first generic declaration, or Object.class if cannot be determined

*/

public static Class getSuperClassGenricType(Class clazz) {

return getSuperClassGenricType(clazz, 0);

}

/**

  • 通过反射,获得定义Class时声明的父类的范型参数的类型. 如public BookManager extends GenricManager

  • @param clazz clazz The class to introspect

  • @param index the Index of the generic ddeclaration,start from 0.

*/

public static Class getSuperClassGenricType(Class clazz, int index)

throws IndexOutOfBoundsException {

Type genType = clazz.getGenericSuperclass();

if (!(genType instanceof ParameterizedType)) {

return Object.class;

}

Type[] params = ((ParameterizedType) genType).getActualTypeArguments();

if (index >= params.length || index < 0) {

return Object.class;

}

if (!(params[index] instanceof Class)) {

return Object.class;

}

return (Class) params[index];

}

}

新建CommonRepository接口,为公共的Reposit接口,该类继承JpaRepository,JpaSpecificationExecutor两个接口,这两个接口中包含了基本的查询。之后在新建Repository就可以直接继承这个公共的CommonRepository接口就可以了,有两个泛型接口,实体类名称和id的类型,T表示实体类名称,ID表示id的类型。代码如下。

@NoRepositoryBean

public interface CommonRepository<T,ID> extends JpaRepository<T, ID>, JpaSpecificationExecutor {

}

新建CommonService类,为公共的Server类,包含了一下基本查询的方法,之后的Server类,只需要继承这个类,就会包含CommonService类中的所有查询方法,不用在每个类都去写一遍,如果有需要更改的话,可以重写继承类中的方法。和Repository接口一样,它也有有两个泛型接口,实体类名称和id的类型,T表示实体类名称,ID表示id的类型。代码如下。

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.data.domain.Page;

import org.springframework.data.domain.Pageable;

import org.springframework.data.domain.Sort;

import org.springframework.data.jpa.domain.Specification;

import org.springframework.transaction.annotation.Transactional;

import java.util.List;

import java.util.Optional;

/**

  • 公共Service

  • @param

  • @param

*/

public class CommonService<T,ID> {

@Autowired(required = false)

private CommonRepository<T, ID> baseDAO;

//查询所有

public List findAll(){

return baseDAO.findAll();

}

//根据id查询

public T findById(ID id) {

Optional optional = baseDAO.findById(id);

if(optional.isPresent()) {

return optional.get();

}

return null;

}

//保存方法

@Transactional

public void save(T entity) {

baseDAO.save(entity);

}

//根据实体类删除

public void delete(T entity) {

baseDAO.delete(entity);

}

//根据id查询

@Transactional

public void deleteById(ID id) {

baseDAO.deleteById(id);

}

//排序查询所有

public List findAll(Sort sort){

return baseDAO.findAll(sort);

}

//动态条件查询

public List findAll(Specification spec){

return baseDAO.findAll(spec);

}

//分页查询

public Page findAll(Pageable pageable){

return baseDAO.findAll(pageable);

}

//动态条件分页查询

public Page findAll(Specification spec, Pageable pageable){

return baseDAO.findAll(spec,pageable);

}

//动态条件排序查询

public List findAll(Specification spec, Sort sort){

return baseDAO.findAll(spec,sort);

}

}

最后就是控制器的封装了,控制器需要先通过反射机制的工具类GenericsUtils,找到对应的实体类。之后封装一下常用的方法。不同于上面两个类的是,他有三个泛型接口,除了实体类和ID的类型外,他还有一个BaseForm类,BaseForm为公共的Form类,该类中就一个id和一个查询条件。因为这里写数据保存方法的数据接收是很使用的Form接收的,使用Form里边的ID是判断是修改还是新增方法(修改和新增用的一个方法,用id是否为null区分),BaseForm类代码如下。

public class BaseForm {

private ID id;

private String search;

public ID getId() {

return id;

}

public void setId(ID id) {

this.id = id;

}

public String getSearch() {

return search;

}

public void setSearch(String search) {

this.search = search;

}

}

其中search字段是BootstrapTable查询传递参数的属性名,所以写在了公共的Form类中,不需要的可以删除不要。

公共的CommonController控制器代码如下(主要包了数据显示,新增修改页面的跳转,和数据查询和删除的方法)。

import org.springframework.beans.BeanUtils;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.data.domain.Page;

import org.springframework.data.domain.PageRequest;

import org.springframework.data.domain.Sort;

import org.springframework.data.jpa.domain.Specification;

import org.springframework.ui.ModelMap;

import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.web.bind.annotation.ResponseBody;

/**

  • 公共Controller

  • @param

  • @param

  • @param

*/

public class CommonController<T, ID, Form extends BaseForm>{

//通过反射工具类GenericsUtils,获得到实体类

@SuppressWarnings(“unchecked”)

private Class clazz = GenericsUtils.getSuperClassGenricType(getClass());

@Autowired

private CommonService<T, ID> baseService;

//数据显示页面

@RequestMapping(value=“/manage”)

public void manage(ModelMap map) {

}

//修改和新增页面,共用的一个页面

@RequestMapping(value=“/edit”)

public void edit(Form form, ModelMap map) throws InstantiationException, IllegalAccessException {

T model=clazz.newInstance();

ID id = form.getId();

if(id!=null) {

model=baseService.findById(id);

}

map.put(“model”, model);

}

//数据保存方法

@RequestMapping(value=“/save”)

@ResponseBody

public Object save(Form form) {

try {

T model=clazz.newInstance();

ID id = form.getId();

if(id!=null) {

model=baseService.findById(id);

}

BeanUtils.copyProperties(form, model,“id”);

baseService.save(model);

return new AjaxResult(“数据保存成功”);

} catch (Exception e) {

return new AjaxResult(false,“数据保存失败”);

}

}

//删除方法

@RequestMapping(value=“/delete”)

@ResponseBody

public Object delete(ID id) {

try {

baseService.deleteById(id);

return new AjaxResult(“数据删除成功”);

} catch (Exception e) {

return new AjaxResult(false,“数据删除失败”);

}

}

//动态查询方法

public Specification buildSpec(Form form){

return null;

}

//分页数据查询

@RequestMapping(value=“/page”)

@ResponseBody

public Object page(TablePageable pageParam,Form form) {

PageRequest pageable = pageParam.bulidPageRequest();

Specification spec = buildSpec(form);

Page page=baseService.findAll(spec, pageable);

return AjaxResult.bulidPageResult(page);

}

}

分页查询中的TablePageable类,是用于接收Bootstraptable传递过来的分页参数,代码如下。

import org.springframework.data.domain.PageRequest;

import org.springframework.data.domain.Sort;

import org.springframework.data.domain.Sort.Direction;

import org.springframework.data.domain.Sort.Order;

/**

  • 分页的一个工具类,接收分页信息

*/

public class TablePageable {

private Integer limit; //分页

private Integer offset;//首记录号(从0开始)

private String sort; //排序字段

private String order; //顺序,逆序

public Integer getLimit() {

return limit;

}

public void setLimit(Integer limit) {

this.limit = limit;

}

public Integer getOffset() {

return offset;

}

public void setOffset(Integer offset) {

this.offset = offset;

}

public String getSort() {

return sort;

}

public void setSort(String sort) {

this.sort = sort;

}

public String getOrder() {

return order;

}

public void setOrder(String order) {

this.order = order;

}

public PageRequest bulidPageRequest() {

int page=(offset!=null&&limit!=null)?offset/limit:0;

int size=limit!=null?limit:10;

if(sort==null) {

return PageRequest.of(page, size);

}else {

Order order2=new Order(Direction.fromString(order), sort);

Sort sort2= Sort.by(order2);

return PageRequest.of(page,size,sort2 );

}

}

public PageRequest bulidPageable(Sort sort) {

int page=(offset!=null&&limit!=null)?offset/limit:0;

int size=limit!=null?limit:10;

return PageRequest.of(page, size, sort);

}

public Sort bulidSort() {

Order order2=new Order(Direction.fromString(order), sort);

Sort sort2= Sort.by(order2);

return sort2;

}

}

分页查询中返回的AjaxResult类中的bulidPageResult方法是用于转载BootstrapTable表格数据的,根据BootstrapTable接收数据的格式来写。代码如下。

import org.springframework.data.domain.Page;

import java.util.HashMap;

/**

  • 方法执行成功后,返回的工具类

*/

public class AjaxResult {

private Boolean success;

private String msg; //提示信息

public Boolean getSuccess() {

return success;

}

public void setSuccess(Boolean success) {

this.success = success;

}

public String getMsg() {

return msg;

}

public void setMsg(String msg) {

this.msg = msg;

}

public AjaxResult(String msg) {

super();

this.success=true;

this.msg = msg;

}

public AjaxResult(Boolean success, String msg) {

super();

this.success = success;

this.msg = msg;

}

@SuppressWarnings(“rawtypes”)

public static HashMap<String, Object> bulidPageResult(Page page) {

HashMap<String, Object> result=new HashMap<>();

result.put(“total”, page.getTotalElements());

result.put(“rows”, page.getContent());

return result;

}

}

TablePageable类和AjaxResult类,根据自己开发需求来写。

封装文件写完了,下面就需要来写一个案例测试一下了。新建一个User实体类,随便给几个字段,用于测试。代码如下。

import javax.persistence.*;

@Entity

@Table(name = “tb_user”)

public class User {

@Id

@GeneratedValue(strategy = GenerationType.IDENTITY)

private Integer id; //主键

private String username; //姓名,username

private String loginName; //用户名,

private Integer age; //年龄

public Integer getId() {

return id;

}

public void setId(Integer id) {

this.id = id;

}

public String getUsername() {

return username;

}

public void setUsername(String username) {

this.username = username;

}

public String getLoginName() {

return loginName;

}

public void setLoginName(String loginName) {

this.loginName = loginName;

}

public Integer getAge() {

return age;

}

public void setAge(Integer age) {

this.age = age;

}

public User() {

}

public User(String username, String loginName, Integer age) {

this.username = username;

this.loginName = loginName;

this.age = age;

}

}

实体类新建完成后,新建对应的Form接收类,继承BaseForm类,代码如下。

import com.mcy.springbootdemo.custom.BaseForm;

public class UserForm extends BaseForm {

private String username; //姓名,username

private String loginName; //登录名

private Integer age; //年龄

public String getUsername() {

return username;

}

public void setUsername(String username) {

this.username = username;

}

public String getLoginName() {

return loginName;

}

public void setLoginName(String loginName) {

this.loginName = loginName;

}

public Integer getAge() {

return age;

}

public void setAge(Integer age) {

this.age = age;

}

}

新建对应的UserRepository类,继承公共的CommonRepository类,泛型传递对应的实体类和ID类型,代码如下。

import com.mcy.springbootdemo.custom.CommonRepository;

import com.mcy.springbootdemo.entity.User;

import org.springframework.stereotype.Repository;

@Repository

public interface UserRepository extends CommonRepository<User, Integer> {

}

新建对应的UserService类,继承公共的CommonService类,泛型也是传递对应的实体类和ID类型,代码如下。

import com.mcy.springbootdemo.custom.CommonService;

import com.mcy.springbootdemo.entity.User;

import org.springframework.stereotype.Service;

@Service

写在最后

还有一份JAVA核心知识点整理(PDF):JVM,JAVA集合,JAVA多线程并发,JAVA基础,Spring原理,微服务,Netty与RPC,网络,日志,Zookeeper,Kafka,RabbitMQ,Hbase,MongoDB,Cassandra,设计模式,负载均衡,数据库,一致性哈希,JAVA算法,数据结构,加密算法,分布式缓存,Hadoop,Spark,Storm,YARN,机器学习,云计算…

image

public void setLoginName(String loginName) {

this.loginName = loginName;

}

public Integer getAge() {

return age;

}

public void setAge(Integer age) {

this.age = age;

}

}

新建对应的UserRepository类,继承公共的CommonRepository类,泛型传递对应的实体类和ID类型,代码如下。

import com.mcy.springbootdemo.custom.CommonRepository;

import com.mcy.springbootdemo.entity.User;

import org.springframework.stereotype.Repository;

@Repository

public interface UserRepository extends CommonRepository<User, Integer> {

}

新建对应的UserService类,继承公共的CommonService类,泛型也是传递对应的实体类和ID类型,代码如下。

import com.mcy.springbootdemo.custom.CommonService;

import com.mcy.springbootdemo.entity.User;

import org.springframework.stereotype.Service;

@Service

写在最后

还有一份JAVA核心知识点整理(PDF):JVM,JAVA集合,JAVA多线程并发,JAVA基础,Spring原理,微服务,Netty与RPC,网络,日志,Zookeeper,Kafka,RabbitMQ,Hbase,MongoDB,Cassandra,设计模式,负载均衡,数据库,一致性哈希,JAVA算法,数据结构,加密算法,分布式缓存,Hadoop,Spark,Storm,YARN,机器学习,云计算…

[外链图片转存中…(img-PQ2nT7gL-1721879727842)]

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值