Spring Boot + Spring Data JPA 项目整合开发记录(持续更新)

空扰寡人 提交于 2019-12-04 05:09:25

刚换了公司,项目架构师提出新的系统架构时还是愣了一下,搭建难度较低,很容易上手,但是对Spring Data JPA的了解不够深入,所以还是有些吃力,在框架搭建初期有许多东西并没有很好的集成。

20180714-这个项目表与表之间的耦合度太低了,且不允许在实体类中进行外键对象关联,一对多、多对一、多对多的关系处理就比较复杂了,Spring Data JPA提供了好几种不同的接口调用方式,因此什么时候使用什么样的方法显得尤为重要,不同的方法编写方式也不太一样,在数据处理方面比较头疼,如果需要抽取不同表之间的数据为结果,要做联合查询且需要额外在声明一个相应的实体类来接受,不然就只能将外键表字段存储到本表中,相当费劲。

 框架体系

Spring Boot + Spring Data JPA + Spring Security + Spring Security oAuth2.0 + Thymeleaf

Spring Boot

Spring Data JPA

Spring Security

Thymeleaf

Vue.js

Vue Element-ui

Node.js 与 NPM(辅助,安装Node后,NPM会附带安装),附带webpack工具、路由等。

实体类中并没有声明任何外键关联关系,因此我们查询了许多种方法来解决外键关联查询并返回结果的方法。

Spring Data JPA - JpaRepository

Spring Data JPA - PagingAndSortingRepository

Spring Data JPA - JpaSpecificationExecutor

Spring Data JPA - Query

Spring Data JPA - QueryDSL

Spring Data JPA - CriteriaBuilder

NPM安装与配置:

配置npm的全局模块的存放路径以及cache的路径,在node根目录下建立node_cache和node_global文件夹。

启动CMD,输入以下命令:

npm config set prefix "D:\DevelopTool\nodejs\node_global"
以及
npm config set cache "D:\DevelopTool\nodejs\node_cache"

安装(Express)测试模块,输入以下命令,-g代表将该插件安装到全局目录中,node_golbal。

npm install express -g

设置环境变量,用户变量下新建"NODE_PATH",输入”D:\DevelopTool\Nodejs\node_global“。

用户变量,修改"PATH",添加“%NODE_PATH%;”。

在D:\DevelopTool\nodejs\node_modules\npm目录下,使用命令行进行安装。

# install dependency
npm install

# develop
npm run dev

 

Spring Boot 与 Spring MVC的区别?

Spring 框架就像一个家族,有众多衍生产品例如 MVC、boot、security、jpa等等。但他们的基础都是Spring 的 ioc和 aop ioc 提供了依赖注入的容器 aop ,解决了面向横切面的编程,然后在此两者的基础上实现了其他延伸产品的高级功能。

Spring MVC是一个前端框架。Spring MVC是基于 Servlet 的一个 MVC 框架 主要解决 WEB 开发的问题,因为 Spring 的配置非常复杂,各种XML、 JavaConfig、hin处理起来比较繁琐。

Spring Boot换而言之,是一个Spring框架的一种形式。

Spring Boot实现了自动配置,降低了项目搭建的复杂度。

众所周知Spring框架需要进行大量的配置,Spring Boot引入自动配置的概念,让项目设置变得很容易。Spring Boot本身并不提供Spring框架的核心特性以及扩展功能,只是用于快速、敏捷地开发新一代基于Spring框架的应用程序。也就是说,它并不是用来替代Spring的解决方案,而是和Spring框架紧密结合用于提升Spring开发者体验的工具。同时它集成了大量常用的第三方库配置(例如Jackson, JDBC, Mongo, Redis, Mail等等),Spring Boot应用中这些第三方库几乎可以零配置的开箱即用(out-of-the-box),大部分的Spring Boot应用都只需要非常少量的配置代码,开发者能够更加专注于业务逻辑。、

DAO层代码示例-20180720重新更新代码(使用countBy、getBy、findBy等内部规定表达式可以完成简单的操作,后续And等,带实体类对应的属性名称即可)

package com.hz.partyorg.dao;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.repository.PagingAndSortingRepository;

import com.hz.partyorg.entity.PartyOrgDeclareBasic;

import java.util.List;

/**
 * 党组织-申报信息与基本信息联合记录
 * @author Wen.C
 */
public interface PartyOrgDeclareBasicDAO extends JpaRepository<PartyOrgDeclareBasic, Long>, 
PagingAndSortingRepository<PartyOrgDeclareBasic,Long>, 
JpaSpecificationExecutor<PartyOrgDeclareBasic> {

    Long countByDzzSbxxId(String dzzSbxxId);

    PartyOrgDeclareBasic getByDzzJbxxIdAndDzzSbxxId(String dzzJbxxId, String dzzSbxxId);

    PartyOrgDeclareBasic getByDzzSbxxIdAndAuditStatus(String dzzSbxxId, String auditStatus);

    List<PartyOrgDeclareBasic> findByDzzSbxxIdAndAuditStatus(String dzzSbxxId, String auditStatus);
}

Service层示例-20180720重新更新代码

package com.hz.partyorg.service;

import java.util.ArrayList;
import java.util.List;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;

import com.hz.common.config.GlobalConfig;
import org.apache.commons.lang3.StringUtils;
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.stereotype.Service;

import com.hz.partyorg.dao.PartyOrgDeclareBasicDAO;
import com.hz.partyorg.entity.PartyOrgDeclareBasic;

/**
 * 党组织-申报信息与基本信息联合记录
 * @author Wen.C
 */
@Service
public class PartyOrgDeclareBasicService {

	@Autowired
    private PartyOrgDeclareBasicDAO partyOrgDeclareBasicDAO;
	
	/**
     * 党组织-申报信息与基本信息联合记录-保存数据
     * @param partyOrgDeclareBasic
     */
    public PartyOrgDeclareBasic save(PartyOrgDeclareBasic partyOrgDeclareBasic) {
        return partyOrgDeclareBasicDAO.save(partyOrgDeclareBasic);
    }

    /**
     * 党组织-申报信息-列表查询,根据传入Type判断,标记为是否为 0-需要审批的数据 1-历史数据
     * @param type 0-需要审批的数据 1-历史数据 null-取消条件
     * @param partyOrgDeclareBasic 实体对象
     * @return
     */
    public List<PartyOrgDeclareBasic> list(Integer type, PartyOrgDeclareBasic partyOrgDeclareBasic){
        Specification<PartyOrgDeclareBasic> spec = new Specification<PartyOrgDeclareBasic>() {
            @Override
            public Predicate toPredicate(Root<PartyOrgDeclareBasic> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
                List<Predicate> list = new ArrayList<>();
                if(null != type && 0 == type){ // 0-需要审批的数据
                    list.add(cb.notEqual(root.get("auditStatus"), GlobalConfig.AUDIT_STATUS_TRANSFER_YES));
                    list.add(cb.notEqual(root.get("auditStatus"), GlobalConfig.AUDIT_STATUS_YES));
                } else if(null != type && 1 == type){ // 1-历史数据
                    list.add(cb.notEqual(root.get("auditStatus"), GlobalConfig.AUDIT_STATUS_WAITE));
                    list.add(cb.notEqual(root.get("auditStatus"), GlobalConfig.AUDIT_STATUS_TRANSFER));
                }
                if(StringUtils.isNotEmpty(partyOrgDeclareBasic.getDzzJbxxId()) && StringUtils.isNotBlank(partyOrgDeclareBasic.getDzzJbxxId())){
                    list.add(cb.equal(root.get("dzzJbxxId"), partyOrgDeclareBasic.getDzzJbxxId()));
                }
                if(StringUtils.isNotEmpty(partyOrgDeclareBasic.getDzzSbxxId()) && StringUtils.isNotBlank(partyOrgDeclareBasic.getDzzSbxxId())){
                    list.add(cb.equal(root.get("dzzSbxxId"), partyOrgDeclareBasic.getDzzSbxxId()));
                }
                Predicate[] p = new Predicate[list.size()];
                return cb.and(list.toArray(p));
            }
        };
        return partyOrgDeclareBasicDAO.findAll(spec ,new Sort(Sort.Direction.DESC, "id"));
    }
    
    /**
     * 党组织-申报信息-分页查询
     * @param partyOrgDeclareBasic 实体对象
     * @param pageNo 当前页码
     * @param pageSize 显示条数
     * @return
     */
    public Page<PartyOrgDeclareBasic> page(PartyOrgDeclareBasic partyOrgDeclareBasic, Integer pageNo, Integer pageSize){
        Specification<PartyOrgDeclareBasic> spec = new Specification<PartyOrgDeclareBasic>() {
            @Override
            public Predicate toPredicate(Root<PartyOrgDeclareBasic> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
                List<Predicate> list = new ArrayList<>();
                if(StringUtils.isNotEmpty(partyOrgDeclareBasic.getDzzSbxxId()) && StringUtils.isNotBlank(partyOrgDeclareBasic.getDzzSbxxId())){
                    list.add(cb.equal(root.get("dzzSbxxId"), partyOrgDeclareBasic.getDzzSbxxId()));
                }
                if(StringUtils.isNotEmpty(partyOrgDeclareBasic.getDzzJbxxId()) && StringUtils.isNotBlank(partyOrgDeclareBasic.getDzzJbxxId())){
					list.add(cb.equal(root.get("dzzJbxxId"), partyOrgDeclareBasic.getDzzJbxxId()));
				}
                if(StringUtils.isNotEmpty(partyOrgDeclareBasic.getAuditResultsTime()) && StringUtils.isNotBlank(partyOrgDeclareBasic.getAuditResultsTime())){
					list.add(cb.equal(root.get("auditResultsTime"), partyOrgDeclareBasic.getAuditResultsTime()));
				}
                Predicate[] p = new Predicate[list.size()];
                return cb.and(list.toArray(p));
            }
        };
        return partyOrgDeclareBasicDAO.findAll(spec ,new PageRequest(pageNo, pageSize, new Sort(Sort.Direction.DESC, "id")));
    }
    
    /**
     * 党组织-申报信息-分页查询(判断条件:auditResultsTime 审批时间 不为空)
     * @param partyOrgDeclareBasic 实体对象
     * @param pageNo 当前页码
     * @param pageSize 显示条数
     * @return
     */
    public Page<PartyOrgDeclareBasic> pageByAuditResultTimeIsNotNull(PartyOrgDeclareBasic partyOrgDeclareBasic, Integer pageNo, Integer pageSize){
        Specification<PartyOrgDeclareBasic> spec = new Specification<PartyOrgDeclareBasic>() {
            @Override
            public Predicate toPredicate(Root<PartyOrgDeclareBasic> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
                List<Predicate> list = new ArrayList<>();
                if(null != partyOrgDeclareBasic.getDzzJbxxId() && StringUtils.isNotBlank(partyOrgDeclareBasic.getDzzJbxxId())){
					list.add(cb.equal(root.get("dzzJbxxId"), partyOrgDeclareBasic.getDzzJbxxId()));
				}
				    list.add(root.get("auditResultsTime").isNotNull());
                Predicate[] p = new Predicate[list.size()];
                return cb.and(list.toArray(p));
            }
        };
        return partyOrgDeclareBasicDAO.findAll(spec ,new PageRequest(pageNo, pageSize, new Sort(Sort.Direction.DESC, "id")));
    }

    /**
     * 根据党组织ID查询记录总数
     * @param dzzSbxxId
     * @return
     */
    public Long countByDzzSbxxId(String dzzSbxxId) {
        return partyOrgDeclareBasicDAO.countByDzzSbxxId(dzzSbxxId);
    }

    /**
     * 根据党组织Id和申报信息Id查询指定数据
     * @param dzzJbxxId
     * @param dzzSbxxId
     * @return
     */
    public PartyOrgDeclareBasic getByDzzJbxxIdAndDzzSbxxId(String dzzJbxxId, String dzzSbxxId) {
        return partyOrgDeclareBasicDAO.getByDzzJbxxIdAndDzzSbxxId(dzzJbxxId, dzzSbxxId);
    }

    /**
     * 根据申报信息Id和审批状态查询指定数据
     * @param dzzSbxxId
     * @param auditStatus
     * @return
     */
    public PartyOrgDeclareBasic getByDzzSbxxIdAndAuditStatus(String dzzSbxxId, String auditStatus) {
        return partyOrgDeclareBasicDAO.getByDzzSbxxIdAndAuditStatus(dzzSbxxId, auditStatus);
    }

    /**
     * 根据申报信息Id和审批状态查询数据返回集合
     * @param dzzSbxxId
     * @param auditStatus
     * @return
     */
    public List<PartyOrgDeclareBasic> findByDzzSbxxIdAndAuditStatus(String dzzSbxxId, String auditStatus) {
        return partyOrgDeclareBasicDAO.findByDzzSbxxIdAndAuditStatus(dzzSbxxId, auditStatus);
    }
}

Manager特殊业务处理层与Dao同级存在,不同业务场景调用(用于关联表查询以及返回联合数据结果)-20180720,使用到QueryDSL。

package com.hz.partyorg.dao;

import com.hz.partyorg.entity.*;
import com.hz.partyorg.vo.PartyOrgDeclareInformationVo;
import com.querydsl.core.Tuple;
import com.querydsl.jpa.impl.JPAQuery;
import com.querydsl.jpa.impl.JPAQueryFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 申报信息、申报与党组织信息联合处理类,联合查询,返回Vo实体类对象,自由封装
 */
@Component
public class PartyOrgDeclareBasicManager {

    @Autowired
    @PersistenceContext
    private EntityManager entityManager;
    private JPAQueryFactory queryFactory;

    @PostConstruct
    public void init() {
        queryFactory = new JPAQueryFactory(entityManager);
    }

    /**
     * 针对申报信息做的联合查询方法
     * @param dzzJbxxId 党组织ID
     * @param dzzSbxxIds 申报信息ID 集合
     * @param pageNo 当前页数
     * @param pageSize 每页显示条数
     * @return
     */
    public  Map<String,Object> findList(String dzzJbxxId, List<Long> dzzSbxxIds, Integer pageNo, Integer pageSize){

        Map<String,Object> result = new HashMap<>();
        QPartyOrgDeclareInformation partyOrgDeclareInformation = QPartyOrgDeclareInformation.partyOrgDeclareInformation;
        QPartyOrgDeclareBasic partyOrgDeclareBasic = QPartyOrgDeclareBasic.partyOrgDeclareBasic;

//        JPAQuery<PartyOrgDeclareInformation> jpaQuery = queryFactory.select(partyOrgDeclareInformation).from(partyOrgDeclareInformation)
//                .leftJoin(partyOrgDeclareBasic)
//                .on(partyOrgDeclareBasic.dzzSbxxId.eq(partyOrgDeclareInformation.id.toString()))
//                .where(partyOrgDeclareInformation.id.in(dzzSbxxIds));

        int jpaQueryPageAllNum = queryFactory.select(partyOrgDeclareInformation, partyOrgDeclareBasic)
                .from(partyOrgDeclareInformation)
                .innerJoin(partyOrgDeclareBasic)
                .on(partyOrgDeclareBasic.dzzSbxxId.eq(partyOrgDeclareInformation.id.stringValue()))
                .where(partyOrgDeclareInformation.id.in(dzzSbxxIds))
                .where(partyOrgDeclareBasic.dzzJbxxId.eq(dzzJbxxId))
                .fetch()
                .size();

        JPAQuery<Tuple> jpaQuery = queryFactory.select(partyOrgDeclareInformation, partyOrgDeclareBasic)
                .from(partyOrgDeclareInformation)
                .innerJoin(partyOrgDeclareBasic)
                .on(partyOrgDeclareBasic.dzzSbxxId.eq(partyOrgDeclareInformation.id.stringValue()))
                .where(partyOrgDeclareInformation.id.in(dzzSbxxIds))
                .where(partyOrgDeclareBasic.dzzJbxxId.eq(dzzJbxxId))
                .offset(pageNo)
                .limit(pageSize);

        List<Tuple> tuples = jpaQuery.fetch();
        List<PartyOrgDeclareInformationVo> voList = new ArrayList<>();
        if(null != tuples && !tuples.isEmpty()){
            for(Tuple tuple:tuples){
                PartyOrgDeclareInformation partyOrgDeclareInformationResult = tuple.get(0, PartyOrgDeclareInformation.class);
                PartyOrgDeclareBasic partyOrgDeclareBasicResult = tuple.get(1, PartyOrgDeclareBasic.class);
                PartyOrgDeclareInformationVo vo = new PartyOrgDeclareInformationVo();
                // 1- 申报信息
                vo.setId(partyOrgDeclareInformationResult.getId());
                vo.setDeclarationTypeName(partyOrgDeclareInformationResult.getDeclarationTypeName());
                vo.setDeclarationItem(partyOrgDeclareInformationResult.getDeclarationItem());
                vo.setDeclarationTime(partyOrgDeclareInformationResult.getDeclarationTime());
                vo.setDeclarer(partyOrgDeclareInformationResult.getDeclarer());
                vo.setDeclarationOrg(partyOrgDeclareInformationResult.getDeclarationOrg());
                vo.setAuditResults(partyOrgDeclareInformationResult.getAuditResults());
                // 2- 申报联合信息
                vo.setAuditStatus(partyOrgDeclareBasicResult.getAuditStatus());
                vo.setAuditStatusName(partyOrgDeclareBasicResult.getAuditStatusName());
                vo.setAuditResultsTime(partyOrgDeclareBasicResult.getAuditResultsTime());
                vo.setDzzJbxxId(Long.valueOf(partyOrgDeclareBasicResult.getDzzJbxxId()));
                voList.add(vo);
            }
        }

        result.put("pageAllNum", jpaQueryPageAllNum);
        result.put("voList", voList);

        return result;
    }

}

知识点

Vue

路由跳转:

this.$router.push({ path: '/partyAffairsManager/partyOrgLifeManager', query: { activeName: 'partyClassRegistration', show: true } });

 

常见问题

Swagger相关

问题描述:

1.主表设置一对多的实体类对应关系@OneToMany;

2.swagger扫描对应的包路径;

报错问题:

项目启动报错,注释掉一对多关系后,可正常启动。

at springfox.documentation.spring.web.readers.parameter.ModelAttributeParameterExpander.expand(ModelAttributeParameterExpander.java:110) ~[springfox-spring-web-2.6.1.jar:2.6.1]

解决办法:

 

数据报错 JPA 多对一属性 persist出错

问题描述:

1.从表设置多对一关系@ManyToOne

报错问题:

进行数据保存时报错。

detached entity passed to persis

解决方法:

 

@Query 注解动态查询无法使用LIMIT关键词

JPQL和原生的SQL,JPQL没有LIMIT关键词

 

Vue Element-ui

相关命令:

# 安装
npm install
# 版本查询
npm ls element-ui
# 卸载
npm uninstall element-ui
# 重新安装
npm i element-ui -S
# 启动项目
npm run dev
# 安装指定版本
npm install element-ui@2.3.7 -S

树型控件 Treeselect

https://vue-treeselect.js.org/#customize-key-names

# 安装命令
npm install --save @riophae/vue-treeselect

时间控件 Moment

# 安装命令
npm install moment 

 

Vue问题记录:

如果没有传递回显数据给表单对象,则回显时,表单控件如Select是点击无反应的。

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!