SpringBoot整合SpringDataJPA

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,集群版 2核4GB 100GB
推荐场景:
搭建个人博客
云数据库 RDS MySQL,高可用版 2核4GB 50GB
简介: SpringBoot整合SpringDataJPA

1 SpringBootData JPA介绍

SpringData:其实SpringData就是Spring提供了一个操作数据的框架。而SpringData JPA只是SpringData框架下的一个基于JPA标准操作数据的模块。

  SpringData JPA:基于JPA的标准数据进行操作。简化操作持久层的代码。只需要编写接口就可以。

2 SpringBoot整合SpringData JPA

1、导入maven依赖

 在原有的SprigBoot的maven依赖的基础下加上JPA的依赖

2、application.properties文件中添加配置

3、实体类

import javax.persistence.*;
@Entity
@Table(name="t_users")
public class Users {
  @Id //主键id
  @GeneratedValue(strategy=GenerationType.IDENTITY)//主键生成策略
  @Column(name="id")//数据库字段名
  private Integer id;
  @Column(name="name")
  private String name;
  @Column(name="age")
  private Integer age;
  @Column(name="address")
  private String address;
  @ManyToOne(cascade = CascadeType.PERSIST) //表示多方
  @JoinColumn(name ="role_id")  //维护一个外键,外键在Users一侧
  private Roles roles;
  public Roles getRoles() {
    return roles;
  }
  public void setRoles(Roles roles) {
    this.roles = roles;
  }
  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 Integer getAge() {
    return age;
  }
  public void setAge(Integer age) {
    this.age = age;
  }
  public String getAddress() {
    return address;
  }
  public void setAddress(String address) {
    this.address = address;
  }
  @Override
  public String toString() {
    final StringBuffer sb = new StringBuffer("Users{");
    sb.append("id=").append(id);
    sb.append(", name='").append(name).append('\'');
    sb.append(", age=").append(age);
    sb.append(", address='").append(address).append('\'');
    sb.append(", roles=").append(roles);
    sb.append('}');
    return sb.toString();
  }
}

4、编写Dao接口

import org.springframework.data.jpa.repository.JpaRepository;
import com.oldlu.pojo.Users;
/**
 * 参数一 T :当前需要映射的实体
 * 参数二 ID :当前映射的实体中的OID的类型
 *
 */
public interface UsersRepository extends JpaRepository<Users,Integer> {
}

6、在pom文件中添加测试启动器的坐标

7、测试

3 SpringBoot JPA提供的核心接口

1、Repository接口

 2、CrudRepository接口

3、PagingAndSortingRepository接口

 4、JpaRepository接口

 5、JPASpecificationExecutor接口

4 Repository接口的使用

提供了方法名称命名查询方式

 提供了基于@Query注解查询与更新

1、dao层接口(方法名称命名查询方式)

import com.oldlu.pojo.Users;
import org.springframework.data.repository.Repository;
import java.util.List;
/**
 * Repository接口方法名称命名查询
 *
 */
public interface UsersRepositoryByName extends Repository<Users,Integer> {
    //方法名称必须要遵循驼峰式命名规则,findBy(关键字)+属性名称(首字母大写)+查询条件(首字母大写)
    List<Users> findByName(String name);
    List<Users> findByNameAndAge(String name,Integer age);
    List<Users> findByNameLike(String name);
}

2、测试

/**
   * Repository
   */
  @Test
  public void UsersRepositoryByName(){
    List<Users> list=this.usersRepositoryByName.findByName("张三");
    for (Users users:list){
      System.out.println(users);
    }
  }
  @Test
  public void findByNameAndAge(){
    List<Users> list=this.usersRepositoryByName.findByNameAndAge("张三",20);
    for (Users users:list){
      System.out.println(users);
    }
  }
  @Test
  public void findByNameLike() {
    List<Users> list = this.usersRepositoryByName.findByNameLike("张%");
    for (Users users : list) {
      System.out.println(users);
    }
  }

3、dao层接口编写(基于@Query注解查询与更新)

import com.oldlu.pojo.Users;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import java.util.List;
/**
 * 〈一句话功能简述〉<br> 
 *  Repository    @Query
 *
 * @author admin
 * @create 2019/5/22
 * @since 1.0.0
 */
public interface UsersRepositoryQueryAnnotation extends JpaRepository<Users,Integer> {
    @Query("from Users where name = ?")
    List<Users> queryByNameUseHQL(String name);
    @Query(value = "select * from t_user where name=?",nativeQuery = true)
    List<Users> queryByNameUseSQL(String name);
    @Query("update Users set name=? where id=?")
    @Modifying  //需要执行一个更新操作
    void updateUsersNameById(String name,Integer id);
}

4、测试

  /**
   * Repository--@Query测试
   */
  @Test
  public void testQueryByNameUseSQL() {
    List<Users> list = this.usersRepositoryQueryAnnotation.queryByNameUseSQL("张三");
    for (Users users : list) {
      System.out.println(users);
    }
  }
  /**
   * Repository--@Query测试
   */
  @Test
  @Transactional //@Transactional与@Test 一起使用时 事务是自动回滚的。
  @Rollback(false) //取消自动回滚
  public void testUpdateUsersNameById() {
    this.usersRepositoryQueryAnnotation.updateUsersNameById("张三三", 1);
  }

5 CrudRepository接口的使用

CrudRepository接口,主要是完成一些增删改查的操作。注意:CrudRepository接口继承了Repository接口

1、编写dao层接口

import com.oldlu.pojo.Users;
import org.springframework.data.repository.CrudRepository;
public interface UsersRepositoryCrudRepository extends CrudRepository<Users,Integer> {
}
123456

2、测试

@Test
  public void testCrudRepositorySave() {
    Users users=new Users();
    users.setName("青衫");
    users.setAge(30);
    users.setAddress("湖南怀化");
    this.usersRepositoryCrudRepository.save(users);
  }
  @Test
  public void testCrudRepositoryUpdate() {
    Users users=new Users();
    users.setId(4);
    users.setName("青");
    users.setAge(18);
    users.setAddress("怀化");
    this.usersRepositoryCrudRepository.save(users);
  }
  @Test
  public void testCrudRepositoryFindOne() {
    Users users=this.usersRepositoryCrudRepository.findOne(4);
    System.out.println(users);
  }
  @Test
  public void testCrudRepositoryFindAll() {
    List<Users> list= (List<Users>) this.usersRepositoryCrudRepository.findAll();
    for (Users user:list){
      System.out.println(user);
    }
  }
  @Test
  public void testCrudRepositoryDeleteById() {
    this.usersRepositoryCrudRepository.delete(4);
  }

6 PagingAndSortingRepository接口的使用

该接口提供了分页与排序的操作,注意:该接口继承了CrudRepository接口

1、编写dao层

import com.oldlu.pojo.Users;
import org.springframework.data.repository.PagingAndSortingRepository;
public interface UsersRepositoryPagingAndSorting extends PagingAndSortingRepository<Users,Integer> {
}
123456

2、测试

@Test
  public void testPagingAndSortingRepositorySort() {
    //Order 定义了排序规则
    Sort.Order order=new Sort.Order(Sort.Direction.DESC,"id");
    //Sort对象封装了排序规则
    Sort sort=new Sort(order);
    List<Users> list= (List<Users>) this.usersRepositoryPagingAndSorting.findAll(sort);
    for (Users users:list){
      System.out.println(users);
    }
  }
  @Test
  public void testPagingAndSortingRepositoryPaging() {
    //Pageable:封装了分页的参数,当前页,煤业显示的条数。注意:它的当前页是从0开始
    //PageRequest(page,size):page表示当前页,size表示每页显示多少条
    Pageable pageable=new PageRequest(1,2);
    Page<Users> page=this.usersRepositoryPagingAndSorting.findAll(pageable);
    System.out.println("数据的总条数:"+page.getTotalElements());
    System.out.println("总页数:"+page.getTotalPages());
    List<Users> list=page.getContent();
    for (Users users:list){
      System.out.println(users);
    }
  }
  @Test
  public void testPagingAndSortingRepositorySortAndPaging() {
    Sort sort=new Sort(new Sort.Order(Sort.Direction.DESC,"id"));
    Pageable pageable=new PageRequest(0,2,sort);
    Page<Users> page=this.usersRepositoryPagingAndSorting.findAll(pageable);
    System.out.println("数据的总条数:"+page.getTotalElements());
    System.out.println("总页数:"+page.getTotalPages());
    List<Users> list=page.getContent();
    for (Users users:list){
      System.out.println(users);
    }
  }

7 JpaRepository接口

该接口继承了PagingAndSortingRepository。对继承的父接口中方法的返回值进行适配。

1、dao层接口编写

/**
 * 参数一 T :当前需要映射的实体
 * 参数二 ID :当前映射的实体中的OID的类型
 *
 */
public interface UsersRepository extends JpaRepository<Users,Integer> {
}

2、测试

/**
   * JpaRepository  排序测试
   */
  @Test
  public void testJpaRepositorySort() {
    //Order 定义了排序规则
    Sort.Order order=new Sort.Order(Sort.Direction.DESC,"id");
    //Sort对象封装了排序规则
    Sort sort=new Sort(order);
    List<Users> list= this.usersRepository.findAll(sort);
    for (Users users:list){
      System.out.println(users);
    }
  }

8 JPASpecificationExecutor接口

该接口主要是提供了多条件查询的支持,并且可以在查询中添加排序与分页。注意JPASpecificationExecutor是单独存在的。完全独立

1、dao层接口编写

import com.oldlu.pojo.Users;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
/**
 * 〈一句话功能简述〉<br> 
 *  JpaSpecificationExecutor
 *
 * @author admin
 * @create 2019/5/23
 * @since 1.0.0
 */
public interface UserRepositorySpecification extends JpaRepository<Users,Integer>,JpaSpecificationExecutor<Users> {
}

2、测试

/**
   * JpaSpecificationExecutor   单条件查询
   */
  @Test
  public void testJpaSpecificationExecutor1() {
    /**
     * Specification:用于封装查查询条件
     */
    Specification<Users> spec=new Specification<Users>() {
      //Predicate:封装了单个查询条件
      /**
       * @param root    对查询对象属性的封装
       * @param criteriaQuery 封装了我们要执行的查询中的各个部分的信息,select from order
       * @param criteriaBuilder 查询条件的构造器
       * @return
       */
      @Override
      public Predicate toPredicate(Root<Users> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
        //where name="张三"
        /**
         * 参数一:查询的属性
         * 参数二:条件的值
         */
        Predicate predicate=criteriaBuilder.equal(root.get("name"),"张三");
        return predicate;
      }
    };
    List<Users> list=this.userRepositorySpecification.findAll(spec);
    for (Users users:list){
      System.out.println(users);
    }
  }
  /**
   * JpaSpecificationExecutor   多条件查询方式一
   */
  @Test
  public void testJpaSpecificationExecutor2() {
    /**
     * Specification:用于封装查查询条件
     */
    Specification<Users> spec=new Specification<Users>() {
      //Predicate:封装了单个查询条件
      /**
       * @param root    对查询对象属性的封装
       * @param criteriaQuery 封装了我们要执行的查询中的各个部分的信息,select from order
       * @param criteriaBuilder 查询条件的构造器
       * @return
       */
      @Override
      public Predicate toPredicate(Root<Users> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
        //where name="张三" and age=20
        /**
         * 参数一:查询的属性
         * 参数二:条件的值
         */
        List<Predicate> list=new ArrayList<>();
        list.add(criteriaBuilder.equal(root.get("name"),"张三"));
        list.add(criteriaBuilder.equal(root.get("age"),20));
        Predicate[] arr=new Predicate[list.size()];
        return criteriaBuilder.and(list.toArray(arr));
      }
    };
    List<Users> list=this.userRepositorySpecification.findAll(spec);
    for (Users users:list){
      System.out.println(users);
    }
  }
  /**
   * JpaSpecificationExecutor   多条件查询方式二
   */
  @Test
  public void testJpaSpecificationExecutor3() {
    /**
     * Specification:用于封装查查询条件
     */
    Specification<Users> spec=new Specification<Users>() {
      //Predicate:封装了单个查询条件
      /**
       * @param root    对查询对象属性的封装
       * @param criteriaQuery 封装了我们要执行的查询中的各个部分的信息,select from order
       * @param criteriaBuilder 查询条件的构造器
       * @return
       */
      @Override
      public Predicate toPredicate(Root<Users> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
        //where name="张三" and age=20
        /**
         * 参数一:查询的属性
         * 参数二:条件的值
         */
        /*List<Predicate> list=new ArrayList<>();
        list.add(criteriaBuilder.equal(root.get("name"),"张三"));
        list.add(criteriaBuilder.equal(root.get("age"),20));
        Predicate[] arr=new Predicate[list.size()];*/
        //(name='张三' and age=20) or id=2
        return criteriaBuilder.or(criteriaBuilder.and(criteriaBuilder.equal(root.get("name"),"张三"),criteriaBuilder.equal(root.get("age"),20)),criteriaBuilder.equal(root.get("id"),1));
      }
    };
    Sort sort=new Sort(new Sort.Order(Sort.Direction.DESC,"id"));
    List<Users> list=this.userRepositorySpecification.findAll(spec,sort);
    for (Users users:list){
      System.out.println(users);
    }
  }

9 实际开发遇到的问题

9.1 org.springframework.data.mapping.PropertyReferenceException: No property created found for type

错误原因:

org.springframework.data.domain.Sort

Sort sort=new Sort(Sort.Direction.DESC,“created_time”);//此处使用了数据库的字段名

    public Sort(Sort.Direction direction, String... properties) {//property对应的是table orm后的Java对象的字段名
        this(direction, (List)(properties == null?new ArrayList():Arrays.asList(properties)));
    }

Sort sort=new Sort(Sort.Direction.DESC,“createdTime”);//table表字段对应的java对象字段名

2017-01-15 20:09:26.396 DEBUG 8604 --- [nio-8080-exec-1] org.hibernate.loader.Loader              : Result set row: 0
2017-01-15 20:09:26.396 DEBUG 8604 --- [nio-8080-exec-1] org.hibernate.loader.Loader              : Result row: 
2017-01-15 20:09:26.410 ERROR 8604 --- [nio-8080-exec-1] com.global.GlobalHandler                 : No property created found for type DailyNews!
org.springframework.data.mapping.PropertyReferenceException: No property created found for type DailyNews!
  at org.springframework.data.mapping.PropertyPath.<init>(PropertyPath.java:77) ~[spring-data-commons-1.12.6.RELEASE.jar:na]
  at org.springframework.data.mapping.PropertyPath.create(PropertyPath.java:329) ~[spring-data-commons-1.12.6.RELEASE.jar:na]
  at org.springframework.data.mapping.PropertyPath.create(PropertyPath.java:309) ~[spring-data-commons-1.12.6.RELEASE.jar:na]
  at org.springframework.data.mapping.PropertyPath.from(PropertyPath.java:272) ~[spring-data-commons-1.12.6.RELEASE.jar:na]
  at org.springframework.data.mapping.PropertyPath.from(PropertyPath.java:243) ~[spring-data-commons-1.12.6.RELEASE.jar:na]
  at org.springframework.data.jpa.repository.query.QueryUtils.toJpaOrder(QueryUtils.java:542) ~[spring-data-jpa-1.10.6.RELEASE.jar:na]
  at org.springframework.data.jpa.repository.query.QueryUtils.toOrders(QueryUtils.java:496) ~[spring-data-jpa-1.10.6.RELEASE.jar:na]
  at org.springframework.data.jpa.repository.query.JpaQueryCreator.complete(JpaQueryCreator.java:169) ~[spring-data-jpa-1.10.6.RELEASE.jar:na]
  at org.springframework.data.jpa.repository.query.JpaQueryCreator.complete(JpaQueryCreator.java:137) ~[spring-data-jpa-1.10.6.RELEASE.jar:na]
  at org.springframework.data.jpa.repository.query.JpaQueryCreator.complete(JpaQueryCreator.java:49) ~[spring-data-jpa-1.10.6.RELEASE.jar:na]
  at org.springframework.data.repository.query.parser.AbstractQueryCreator.createQuery(AbstractQueryCreator.java:88) ~[spring-data-commons-1.12.6.RELEASE.jar:na]
  at org.springframework.data.jpa.repository.query.PartTreeJpaQuery$QueryPreparer.createQuery(PartTreeJpaQuery.java:136) ~[spring-data-jpa-1.10.6.RELEASE.jar:na]
  at org.springframework.data.jpa.repository.query.PartTreeJpaQuery.doCreateQuery(PartTreeJpaQuery.java:78) ~[spring-data-jpa-1.10.6.RELEASE.jar:na]
  at org.springframework.data.jpa.repository.query.AbstractJpaQuery.createQuery(AbstractJpaQuery.java:190) ~[spring-data-jpa-1.10.6.RELEASE.jar:na]
  at org.springframework.data.jpa.repository.query.JpaQueryExecution$PagedExecution.doExecute(JpaQueryExecution.java:193) ~[spring-data-jpa-1.10.6.RELEASE.jar:na]
  at org.springframework.data.jpa.repository.query.JpaQueryExecution.execute(JpaQueryExecution.java:82) ~[spring-data-jpa-1.10.6.RELEASE.jar:na]
  at org.springframework.data.jpa.repository.query.AbstractJpaQuery.doExecute(AbstractJpaQuery.java:116) ~[spring-data-jpa-1.10.6.RELEASE.jar:na]
  at org.springframework.data.jpa.repository.query.AbstractJpaQuery.execute(AbstractJpaQuery.java:106) ~[spring-data-jpa-1.10.6.RELEASE.jar:na]
  at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.doInvoke(RepositoryFactorySupport.java:482) ~[spring-data-commons-1.12.6.RELEASE.jar:na]
  at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:460) ~[spring-data-commons-1.12.6.RELEASE.jar:na]
  at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) ~[spring-aop-4.3.5.RELEASE.jar:4.3.5.RELEASE]
  at org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:61) ~[spring-data-commons-1.12.6.RELEASE.jar:na]
  at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) ~[spring-aop-4.3.5.RELEASE.jar:4.3.5.RELEASE]
  at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:99) ~[spring-tx-4.3.5.RELEASE.jar:4.3.5.RELEASE]
  at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:282) ~[spring-tx-4.3.5.RELEASE.jar:4.3.5.RELEASE]
  at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96) ~[spring-tx-4.3.5.RELEASE.jar:4.3.5.RELEASE]
  at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) ~[spring-aop-4.3.5.RELEASE.jar:4.3.5.RELEASE]
  at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:136) ~[spring-tx-4.3.5.RELEASE.jar:4.3.5.RELEASE]
  at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) ~[spring-aop-4.3.5.RELEASE.jar:4.3.5.RELEASE]
  at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPostProcessor.java:133) ~[spring-data-jpa-1.10.6.RELEASE.jar:na]
  at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) ~[spring-aop-4.3.5.RELEASE.jar:4.3.5.RELEASE]
  at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92) ~[spring-aop-4.3.5.RELEASE.jar:4.3.5.RELEASE]
  at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) ~[spring-aop-4.3.5.RELEASE.jar:4.3.5.RELEASE]
  at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:213) ~[spring-aop-4.3.5.RELEASE.jar:4.3.5.RELEASE]
  at com.sun.proxy.$Proxy98.findByStatus(Unknown Source) ~[na:na]

9.2 插入数据时 Duplicate entry ‘admin’ for key ‘name’

插入时看字段是否有Unique索引,或者唯一主键.

Error updating database. Cause: com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Duplicate entry ‘admin’ for key ‘username’
The error may involve com.db.sys.dao.SysUserDao.insertObject-Inline
The error occurred while setting parameters
SQL: insert into sys_users (username,password,deptId,email,mobile,salt,valid, createdTime,modifiedTime,createdUser,modifiedUser) values (?,?,?,?,?,?,?, now(),now(),?,?)
Cause: com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Duplicate entry ‘admin’ for key ‘username’
; SQL []; Duplicate entry ‘admin’ for key ‘username’; nested exception is com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Duplicate entry ‘admin’ for key ‘username’
at org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator.doTranslate(SQLErrorCodeSQLExceptionTranslator.java:239)
at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:73)
at org.mybatis.spring.MyBatisExceptionTranslator.translateExceptionIfPossible(MyBatisExceptionTranslator.java:73)
at org.mybatis.spring.SqlSessionTemplate S q l S e s s i o n I n t e r c e p t o r . i n v o k e ( S q l S e s s i o n T e m p l a t e . j a v a : 446 ) a t c o m . s u n . p r o x y . SqlSessionInterceptor.invoke(SqlSessionTemplate.java:446) at com.sun.proxy. SqlSessionInterceptor.invoke(SqlSessionTemplate.java:446)atcom.sun.proxy.Proxy643.insert(Unknown Source)
at org.mybatis.spring.SqlSessionTemplate.insert(SqlSessionTemplate.java:278)
at org.apache.ibatis.binding.MapperMethod.execute(MapperMethod.java:51)
at org.apache.ibatis.binding.MapperProxy.invoke(MapperProxy.java:52)
at com.sun.proxy. P r o x y 645. i n s e r t O b j e c t ( U n k n o w n S o u r c e ) a t c o m . d b . s y s . s e r v i c e . i m p l . S y s U s e r S e r v i c e I m p l . s a v e O b j e c t ( S y s U s e r S e r v i c e I m p l . j a v a : 102 ) a t c o m . d b . s y s . c o n t r o l l e r . S y s U s e r C o n t r o l l e r . d o S a v e O b j e c t ( S y s U s e r C o n t r o l l e r . j a v a : 56 ) a t s u n . r e f l e c t . N a t i v e M e t h o d A c c e s s o r I m p l . i n v o k e 0 ( N a t i v e M e t h o d ) a t s u n . r e f l e c t . N a t i v e M e t h o d A c c e s s o r I m p l . i n v o k e ( U n k n o w n S o u r c e ) a t s u n . r e f l e c t . D e l e g a t i n g M e t h o d A c c e s s o r I m p l . i n v o k e ( U n k n o w n S o u r c e ) a t j a v a . l a n g . r e f l e c t . M e t h o d . i n v o k e ( U n k n o w n S o u r c e ) a t o r g . s p r i n g f r a m e w o r k . w e b . m e t h o d . s u p p o r t . I n v o c a b l e H a n d l e r M e t h o d . d o I n v o k e ( I n v o c a b l e H a n d l e r M e t h o d . j a v a : 205 ) a t o r g . s p r i n g f r a m e w o r k . w e b . m e t h o d . s u p p o r t . I n v o c a b l e H a n d l e r M e t h o d . i n v o k e F o r R e q u e s t ( I n v o c a b l e H a n d l e r M e t h o d . j a v a : 133 ) a t o r g . s p r i n g f r a m e w o r k . w e b . s e r v l e t . m v c . m e t h o d . a n n o t a t i o n . S e r v l e t I n v o c a b l e H a n d l e r M e t h o d . i n v o k e A n d H a n d l e ( S e r v l e t I n v o c a b l e H a n d l e r M e t h o d . j a v a : 97 ) a t o r g . s p r i n g f r a m e w o r k . w e b . s e r v l e t . m v c . m e t h o d . a n n o t a t i o n . R e q u e s t M a p p i n g H a n d l e r A d a p t e r . i n v o k e H a n d l e r M e t h o d ( R e q u e s t M a p p i n g H a n d l e r A d a p t e r . j a v a : 827 ) a t o r g . s p r i n g f r a m e w o r k . w e b . s e r v l e t . m v c . m e t h o d . a n n o t a t i o n . R e q u e s t M a p p i n g H a n d l e r A d a p t e r . h a n d l e I n t e r n a l ( R e q u e s t M a p p i n g H a n d l e r A d a p t e r . j a v a : 738 ) a t o r g . s p r i n g f r a m e w o r k . w e b . s e r v l e t . m v c . m e t h o d . A b s t r a c t H a n d l e r M e t h o d A d a p t e r . h a n d l e ( A b s t r a c t H a n d l e r M e t h o d A d a p t e r . j a v a : 85 ) a t o r g . s p r i n g f r a m e w o r k . w e b . s e r v l e t . D i s p a t c h e r S e r v l e t . d o D i s p a t c h ( D i s p a t c h e r S e r v l e t . j a v a : 967 ) a t o r g . s p r i n g f r a m e w o r k . w e b . s e r v l e t . D i s p a t c h e r S e r v l e t . d o S e r v i c e ( D i s p a t c h e r S e r v l e t . j a v a : 901 ) a t o r g . s p r i n g f r a m e w o r k . w e b . s e r v l e t . F r a m e w o r k S e r v l e t . p r o c e s s R e q u e s t ( F r a m e w o r k S e r v l e t . j a v a : 970 ) a t o r g . s p r i n g f r a m e w o r k . w e b . s e r v l e t . F r a m e w o r k S e r v l e t . d o P o s t ( F r a m e w o r k S e r v l e t . j a v a : 872 ) a t j a v a x . s e r v l e t . h t t p . H t t p S e r v l e t . s e r v i c e ( H t t p S e r v l e t . j a v a : 648 ) a t o r g . s p r i n g f r a m e w o r k . w e b . s e r v l e t . F r a m e w o r k S e r v l e t . s e r v i c e ( F r a m e w o r k S e r v l e t . j a v a : 846 ) a t j a v a x . s e r v l e t . h t t p . H t t p S e r v l e t . s e r v i c e ( H t t p S e r v l e t . j a v a : 729 ) a t o r g . a p a c h e . c a t a l i n a . c o r e . A p p l i c a t i o n F i l t e r C h a i n . i n t e r n a l D o F i l t e r ( A p p l i c a t i o n F i l t e r C h a i n . j a v a : 292 ) a t o r g . a p a c h e . c a t a l i n a . c o r e . A p p l i c a t i o n F i l t e r C h a i n . d o F i l t e r ( A p p l i c a t i o n F i l t e r C h a i n . j a v a : 207 ) a t o r g . a p a c h e . t o m c a t . w e b s o c k e t . s e r v e r . W s F i l t e r . d o F i l t e r ( W s F i l t e r . j a v a : 52 ) a t o r g . a p a c h e . c a t a l i n a . c o r e . A p p l i c a t i o n F i l t e r C h a i n . i n t e r n a l D o F i l t e r ( A p p l i c a t i o n F i l t e r C h a i n . j a v a : 240 ) a t o r g . a p a c h e . c a t a l i n a . c o r e . A p p l i c a t i o n F i l t e r C h a i n . d o F i l t e r ( A p p l i c a t i o n F i l t e r C h a i n . j a v a : 207 ) a t o r g . a p a c h e . c a t a l i n a . c o r e . S t a n d a r d W r a p p e r V a l v e . i n v o k e ( S t a n d a r d W r a p p e r V a l v e . j a v a : 212 ) a t o r g . a p a c h e . c a t a l i n a . c o r e . S t a n d a r d C o n t e x t V a l v e . i n v o k e ( S t a n d a r d C o n t e x t V a l v e . j a v a : 94 ) a t o r g . a p a c h e . c a t a l i n a . a u t h e n t i c a t o r . A u t h e n t i c a t o r B a s e . i n v o k e ( A u t h e n t i c a t o r B a s e . j a v a : 492 ) a t o r g . a p a c h e . c a t a l i n a . c o r e . S t a n d a r d H o s t V a l v e . i n v o k e ( S t a n d a r d H o s t V a l v e . j a v a : 141 ) a t o r g . a p a c h e . c a t a l i n a . v a l v e s . E r r o r R e p o r t V a l v e . i n v o k e ( E r r o r R e p o r t V a l v e . j a v a : 80 ) a t o r g . a p a c h e . c a t a l i n a . v a l v e s . A b s t r a c t A c c e s s L o g V a l v e . i n v o k e ( A b s t r a c t A c c e s s L o g V a l v e . j a v a : 620 ) a t o r g . a p a c h e . c a t a l i n a . c o r e . S t a n d a r d E n g i n e V a l v e . i n v o k e ( S t a n d a r d E n g i n e V a l v e . j a v a : 88 ) a t o r g . a p a c h e . c a t a l i n a . c o n n e c t o r . C o y o t e A d a p t e r . s e r v i c e ( C o y o t e A d a p t e r . j a v a : 502 ) a t o r g . a p a c h e . c o y o t e . h t t p 11. A b s t r a c t H t t p 11 P r o c e s s o r . p r o c e s s ( A b s t r a c t H t t p 11 P r o c e s s o r . j a v a : 1152 ) a t o r g . a p a c h e . c o y o t e . A b s t r a c t P r o t o c o l Proxy645.insertObject(Unknown Source) at com.db.sys.service.impl.SysUserServiceImpl.saveObject(SysUserServiceImpl.java:102) at com.db.sys.controller.SysUserController.doSaveObject(SysUserController.java:56) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) at java.lang.reflect.Method.invoke(Unknown Source) at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:205) at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:133) at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:97) at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:827) at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:738) at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85) at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:967) at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:901) at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:970) at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:872) at javax.servlet.http.HttpServlet.service(HttpServlet.java:648) at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:846) at javax.servlet.http.HttpServlet.service(HttpServlet.java:729) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:292) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207) at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207) at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:212) at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:94) at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:492) at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:141) at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:80) at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:620) at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:88) at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:502) at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1152) at org.apache.coyote.AbstractProtocol Proxy645.insertObject(UnknownSource)atcom.db.sys.service.impl.SysUserServiceImpl.saveObject(SysUserServiceImpl.java:102)atcom.db.sys.controller.SysUserController.doSaveObject(SysUserController.java:56)atsun.reflect.NativeMethodAccessorImpl.invoke0(NativeMethod)atsun.reflect.NativeMethodAccessorImpl.invoke(UnknownSource)atsun.reflect.DelegatingMethodAccessorImpl.invoke(UnknownSource)atjava.lang.reflect.Method.invoke(UnknownSource)atorg.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:205)atorg.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:133)atorg.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:97)atorg.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:827)atorg.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:738)atorg.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85)atorg.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:967)atorg.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:901)atorg.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:970)atorg.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:872)atjavax.servlet.http.HttpServlet.service(HttpServlet.java:648)atorg.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:846)atjavax.servlet.http.HttpServlet.service(HttpServlet.java:729)atorg.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:292)atorg.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207)atorg.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)atorg.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240)atorg.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207)atorg.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:212)atorg.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:94)atorg.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:492)atorg.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:141)atorg.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:80)atorg.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:620)atorg.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:88)atorg.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:502)atorg.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1152)atorg.apache.coyote.AbstractProtocolAbstractConnectionHandler.process(AbstractProtocol.java:684)
at org.apache.tomcat.util.net.NioEndpoint S o c k e t P r o c e s s o r . d o R u n ( N i o E n d p o i n t . j a v a : 1539 ) a t o r g . a p a c h e . t o m c a t . u t i l . n e t . N i o E n d p o i n t SocketProcessor.doRun(NioEndpoint.java:1539) at org.apache.tomcat.util.net.NioEndpoint SocketProcessor.doRun(NioEndpoint.java:1539)atorg.apache.tomcat.util.net.NioEndpointSocketProcessor.run(NioEndpoint.java:1495)
at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor W o r k e r . r u n ( U n k n o w n S o u r c e ) a t o r g . a p a c h e . t o m c a t . u t i l . t h r e a d s . T a s k T h r e a d Worker.run(Unknown Source) at org.apache.tomcat.util.threads.TaskThread Worker.run(UnknownSource)atorg.apache.tomcat.util.threads.TaskThreadWrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Unknown Source)
Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Duplicate entry ‘admin’ for key ‘username’
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(Unknown Source)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(Unknown Source)
at java.lang.reflect.Constructor.newInstance(Unknown Source)
at com.mysql.jdbc.Util.handleNewInstance(Util.java:425)
at com.mysql.jdbc.Util.getInstance(Util.java:408)
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:935)
at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3970)
at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3906)
at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:2524)
at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2677)
at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2549)
at com.mysql.jdbc.PreparedStatement.executeInternal(PreparedStatement.java:1861)
at com.mysql.jdbc.PreparedStatement.execute(PreparedStatement.java:1192)
at com.alibaba.druid.pool.DruidPooledPreparedStatement.execute(DruidPooledPreparedStatement.java:498)
at org.apache.ibatis.executor.statement.PreparedStatementHandler.update(PreparedStatementHandler.java:44)
at org.apache.ibatis.executor.statement.RoutingStatementHandler.update(RoutingStatementHandler.java:69)
at org.apache.ibatis.executor.SimpleExecutor.doUpdate(SimpleExecutor.java:48)
at org.apache.ibatis.executor.BaseExecutor.update(BaseExecutor.java:105)
at org.apache.ibatis.executor.CachingExecutor.update(CachingExecutor.java:71)
at org.apache.ibatis.session.defaults.DefaultSqlSession.update(DefaultSqlSession.java:152)
at org.apache.ibatis.session.defaults.DefaultSqlSession.insert(DefaultSqlSession.java:141)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:433)
… 45 more

9.3 Spring Data JPA@Transient 理解

transient使用小结

1)一旦变量被transient修饰,变量将不再是对象持久化的一部分,该变量内容在序列化后无法获得访问。

2)transient关键字只能修饰变量,而不能修饰方法和类。注意,本地变量是不能被transient关键字修饰的。变量如果是用户自定义类变量,则该类需要实现Serializable接口。


3)被transient关键字修饰的变量不再能被序列化,一个静态变量不管是否被transient修饰,均不能被序列化。


科普下序列化反序列化持久层持久化,序列化实体类变成json等格式,反序列化就是json变成实体类,持久层就是保存到数据库,持久化保存到数据库的数据的特性。


transient的作用


我们都知道一个对象只要实现了Serilizable接口,这个对象就可以被序列化,java的这种序列化模式为开发者提供了很多便利,我们可以不必关系具体序列化的过程,只要这个类实现了Serilizable接口,这个类的所有属性和方法都会自动序列化。


然而在实际开发过程中,我们常常会遇到这样的问题,这个类的有些属性需要序列化,而其他属性不需要被序列化,打个比方,如果一个用户有一些敏感信息(如密码,银行卡号等),为了安全起见,不希望在网络操作(主要涉及到序列化操作,本地序列化缓存也适用)中被传输,这些信息对应的变量就可以加上transient关键字。换句话说,这个字段的生命周期仅存于调用者的内存中而不会写到磁盘里持久化。


总之,java 的transient关键字为我们提供了便利,你只需要实现Serilizable接口,将不需要序列化的属性前添加关键字transient,序列化对象的时候,这个属性就不会序列化到指定的目的地中。

简单地说,@transient 就是在给某个javabean上需要添加个属性,但是这个属性你又不希望给存到数据库中去,仅仅是做个非静态的临时变量,用一下。不修改已经存在数据库的数据的数据结构。注意记得getter和setter!

9.4 更新问题

有时候更新操作会把null值也进行更新,将更新的字段填满,将需要更改的字段重新赋值即可

 /**
     * 更新开庭人员状态
     */
    @ApiOperation(value = "1. 更新开庭人员状态或新增开庭人员", notes = "1. 更新开庭人员状态或新增开庭人员")
    @PostMapping("/save")
    public Object save(@RequestBody SchedulingMember schedulingMember) {
        Long id = schedulingMember.getId();
        if (id != null) {
            SchedulingMember schedulingMemberUpdate = schedulingMemberRepository.findById(id).get();
            BeanUtils.copyProperties(schedulingMember, schedulingMemberUpdate, getNullPropertyNames(schedulingMember));
            return schedulingMemberRepository.save(schedulingMemberUpdate);
        } else {
            return schedulingMemberRepository.save(schedulingMember);
        }
    }

9.5 spring data jpa返回结果无法转换

org.springframework.core.convert.ConversionFailedException: Failed to convert from type [java.lang.Object[]] to type [com.jzh.graduation.entity.SysPermission] for value ‘{1, 权限管理, /sys/permission/**}’; nested exception is org.springframework.core.convert.ConverterNotFoundException: No converter found capable of converting from type [java.lang.Integer] to type [com.jzh.graduation.entity.SysPermission]


原因:返回结果应该转换为对象SysPermission,JPA原生sql写在SysUserDao下(返回结果转换为SysUser),返回结果无法转换,应该写在SysPermissionDao下。

相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
目录
相关文章
|
Java Maven Spring
SpringBoot中整合SpringDataJPA
SpringData:其实SpringData就是Spring提供了一个操作数据的框架。而SpringData JPA只是SpringData框架下的一个基于JPA标准操作数据的模块 SpringData JPA:基于JPA的标准数据进行操作。简化操作持久层的代码。只需要编写接口就可以
85 0
|
SQL 前端开发 Java
基于Springboot+SpringDataJpa+Mysql智能停车管理系统
基于Springboot+SpringDataJpa+Mysql智能停车管理系统
199 0
基于Springboot+SpringDataJpa+Mysql智能停车管理系统
|
SQL 设计模式 JSON
基于SpringBoot+SpringDataJPA+Mysql的课表排课及实验室机房管理系统
基于SpringBoot+SpringDataJPA+Mysql的课表排课及实验室机房管理系统
217 0
基于SpringBoot+SpringDataJPA+Mysql的课表排课及实验室机房管理系统
|
Java 测试技术 Spring
SpringBoot整合SpringDataJPA
通过前面多篇文件对SpringDataJPA的介绍,相信大家应该已经对SpringDataJPA很熟悉了,使用起来还是蛮方便的,只是在整合的时候需要添加大量的配置文件,本文来给大家介绍下SpringBoot整合SpringDataJPA的过程
SpringBoot整合SpringDataJPA
|
1天前
|
JavaScript Java 测试技术
基于SpringBoot+Vue+uniapp的宠物服务中心的详细设计和实现(源码+lw+部署文档+讲解等)
基于SpringBoot+Vue+uniapp的宠物服务中心的详细设计和实现(源码+lw+部署文档+讲解等)
17 6
基于SpringBoot+Vue+uniapp的宠物服务中心的详细设计和实现(源码+lw+部署文档+讲解等)
|
1天前
|
JavaScript Java 测试技术
基于SpringBoot+Vue的房地产销售管理系统的详细设计和实现(源码+lw+部署文档+讲解等)
基于SpringBoot+Vue的房地产销售管理系统的详细设计和实现(源码+lw+部署文档+讲解等)
18 8
|
1天前
|
JavaScript Java 测试技术
基于SpringBoot+Vue+uniapp的房地产销售管理系统的详细设计和实现(源码+lw+部署文档+讲解等)
基于SpringBoot+Vue+uniapp的房地产销售管理系统的详细设计和实现(源码+lw+部署文档+讲解等)
17 7
|
1天前
|
JavaScript Java 测试技术
基于SpringBoot+Vue的成都某幼儿园兴趣班报名管理系统的详细设计和实现(源码+lw+部署文档+讲解等)
基于SpringBoot+Vue的成都某幼儿园兴趣班报名管理系统的详细设计和实现(源码+lw+部署文档+讲解等)
23 7
|
1天前
|
JavaScript Java 测试技术
基于SpringBoot+Vue的果蔬种植销售一体化服务平台的详细设计和实现(源码+lw+部署文档+讲解等)
基于SpringBoot+Vue的果蔬种植销售一体化服务平台的详细设计和实现(源码+lw+部署文档+讲解等)
22 6
|
1天前
|
JavaScript Java 测试技术
基于SpringBoot+Vue的护肤品推荐系统的详细设计和实现(源码+lw+部署文档+讲解等)
基于SpringBoot+Vue的护肤品推荐系统的详细设计和实现(源码+lw+部署文档+讲解等)
14 6