SpringBoot入门项目-基于JPA的App日记后台系统之数据库的创建与JPA的CRUD(二)

提要

本系列文章主要为带领SpringBoot初学者入门,本人也是一名初学者,文章若有不足之处,还望大家提出批评,加以指正!

注意:本系列文章为项目入门篇,非SpringBoot基础入门篇,如无SpringBoot相关基础的童鞋推荐慕课网廖师兄的入门教程

[2小时学会Spring Boot]
[Spring Boot进阶之Web进阶]

本人的开发环境及软件版本(仅供参考)

操作系统 : macOS 10.13.2 
JDK : 1.8
Tomcat : 8.5.27
IntelliJ IDEA : 2017.3.2 (Ultimate Edition)
MySQL : 5.7.21
Reids : 4.0.7

目录


数据库的配置

数据库的创建

在上一章节的文章中我有提到本项目中所使用的数据库为MySQL,数据库的图形化管理软件我个人推荐使用Navicat。

现在我们来回顾一下上一章所提到的application.yml文件中MySQL数据库的配置信息。

spring:
  datasource:
    url: jdbc:mysql://127.0.0.1/test0110?characterEncoding=utf-8&useSSL=false
    username: root
    password: 123456

我们之前也提到了url中的test0110为数据库的名称,所以我们在运行项目之前必须先创建数据库,否则运行会直接报错!

下面我们将通过Navicat这个软件来新建数据库。
新建数据库1
我们通过选中本地/远程的数据库,右键选择新建数据库
新建数据库2
根据图中所填写的信息进行填写,数据库名可根据个人喜好自行更改。(注意,application.yml文件中的数据库url路径里的数据库名必须与你所创建的数据库名保持一致)
点击确定后数据库即新建完成。


数据库表的建立

本项目中只需建立两张表便可实现需求,分别为UserInfo表和NoteInfo表,下面我们将通过代码来建立表与字段。

首先我们先建立entity包,在包下新建UserInfoEntity类与NoteInfoEntity类。

UserInfoEntity类

@Entity
@Table(name = "user_info")
@Data
public class UserInfoEntity {

    @Id
    private String userId;

    private String userName;

    private String userPwd;

    private Integer userSex;

    private String userProfile;

    private String avatarUrl = "https://pic2.zhimg.com/50/v2-d757e91a15dde9792a1850aed2f1a1c8_hd.jpg";


    public UserInfoEntity() {

    }
}

NoteInfoEntity类

@Entity
@Data
@DynamicUpdate
@Table(name = "note_info")
public class NoteInfoEntity {

    @Id
    @GeneratedValue
    private Long noteId;

    private String userId;

    private String noteTitle;

    private String noteContent;

    @UpdateTimestamp
    private Date updateTime;


    public NoteInfoEntity() {

    }
}

注解说明

@Entity 注解表示指定当前的类与数据库中的表进行映射,一个类对应一张表,一个变量对应一个字段。
@Table 注解表示指定当前类对应的表名。
@DynamicUpdate 注解表示当前类中的Date属性会动态更新。
@Data 注解为lombok中的注解,表示自动为你生成get/set方法,让你的代码更加整洁。
@Id 代表为主键。
@GeneratedValue 代表为自增。
@UpdateTimestamp 指示其自动更新。
数据库说明:
Data类中的变量名与数据库中字段名对应规则举栗:userName -> user_name

通过上一章节所提到的application.yml文件中的片段

  jpa:
    hibernate:
      ddl-auto: update

可实现运行项目后根据标注了@Entity注解的类进行表与字段的更新,如数据库中无对应的表,则会自动创建。


JPA中Repository接口说明

数据库的表与字段都已经创建完毕了,接下来我们该干什么呢?没错,接下来我们将要对数据库进行增删查改相关操作。
我们先创建repository包,在repository包下分别创建NoteRepository接口和UserRepository接口,两个接口都需继承JpaRepository接口,让我们来先看一下JpaRepository接口里是什么内容。

JpaRepository接口

@NoRepositoryBean
public interface JpaRepository<T, ID extends Serializable> extends PagingAndSortingRepository<T, ID>, QueryByExampleExecutor<T> {
    List<T> findAll();

    List<T> findAll(Sort var1);

    List<T> findAll(Iterable<ID> var1);

    <S extends T> List<S> save(Iterable<S> var1);

    void flush();

    <S extends T> S saveAndFlush(S var1);

    void deleteInBatch(Iterable<T> var1);

    void deleteAllInBatch();

    T getOne(ID var1);

    <S extends T> List<S> findAll(Example<S> var1);

    <S extends T> List<S> findAll(Example<S> var1, Sort var2);
}

我们可以看到JpaRepository接口又继承于PagingAndSortingRepository接口与QueryByExampleExecutor接口,其中PagingAndSortingRepository接口中包含了两个findAll()方法

    //用于迭代
    Iterable<T> findAll(Sort var1);
    //用于分页
    Page<T> findAll(Pageable var1);

其中返回类型为Page的我们项目后面会使用到,用于分页功能。Iterable在此不做讲解,如有兴趣的童鞋可自行查找相关资料。通过这里我们便可以知道jpa就是通过repository来对数据库进行CRUD操作的。

NoteRepository接口

//JpaRepository中包含两个输入参数,一个是泛型,对应指定的entity,一个是Id的类型
public interface NoteRepository extends JpaRepository<NoteInfoEntity, Long> {
    //查找指定用户的日记列表,并根据更新时间倒序排序后以分页的形式进行获取
    Page<NoteInfoEntity> findByUserIdOrderByUpdateTimeDesc(String userId, Pageable pageable);
}

这里需要说明的是findByUserIdOrderByUpdateTimeDesc这个方法,在JpaRepository接口中进行数据的CRUD的时候,默认的几个方法便是findOne(id),findAll(),save(),update()和delete()等,如果需要根据用户自定义的条件进行查询的话,需要自己在该接口中写对应的方法。然而这个方法是有规矩可寻的,并不是乱写的。
findByUserIdOrderByUpdateTimeDesc这个方法的目的就是为了查找某个用户下的所有日记,并以更新时间倒序排序后的格式输出。那么findByUserId这个就是根据userId来进行查找,如果你写成userid是不会通过的,比如根据你给定的字段名来进行定义,OrderByUpdateTimeDesc的含义就是根据updateTime这个字段来倒序(desc)排序后进行输出。其他方法同理,如有不懂之处可网上自行搜索相关资料。

UserRepository接口

//JpaRepository中包含两个输入参数,一个是泛型,对应指定的entity,一个是Id的类型
public interface UserRepository extends JpaRepository<UserInfoEntity, String> {

}

新建Service进行CRUD操作

到此我们的准备工作已经完毕,接下来便是本章内容的重头戏了!调用JpaRepository接口进行CRUD!小伙伴们是不是也很激动啊!?
先别激动,拿稳鼠标,放稳键盘,深呼吸一口!我们先新建一个service包,在service包下新建两个接口,NoteService接口和UserService接口。

NoteService接口

public interface NoteService {
    //获取用户下的所有日记列表(分页获取)
    Page<NoteInfoVO> noteList(HttpServletRequest request, Pageable pageable) throws Exception;
    //更新某个指定的日记
    NoteInfoVO updateNote(HttpServletRequest request, UserNoteDTO userNoteDTO) throws Exception;
    // 添加日记
    NoteInfoVO addNote(HttpServletRequest request, UserNoteDTO userNoteDTO) throws Exception;
    //删除日记
    void delNote(HttpServletRequest request, UserNoteDTO userNoteDTO) throws Exception;

}

UserService接口

public interface UserService {
    //用户注册
    UserInfoVO userRegister(UserInfoEntity userInfoEntity) throws Exception;
    //用户登录
    UserInfoVO userLogin(UserLoginEntity loginEntity, HttpServletResponse servletResponse) throws Exception;
    //更新密码
    void updatePwd(HttpServletRequest request, UserInfoDTO userInfoDTO) throws Exception;
    //更新个人简介
    void updateProfile(HttpServletRequest request, UserInfoDTO userInfoDTO) throws Exception;
    //获取个人信息
    UserInfoVO userInfo(HttpServletRequest request) throws Exception;
    //用户退出登录(可忽略)
    void userLogout(HttpServletRequest request) throws Exception;
}

看到这里可能有些小伙伴会有点懵逼,这传入的参数都是些啥啊?这里我给大家解释一下,HttpServletRequest这个参数是为了获取请求Cookie中的token和userId参数,用于用户权限校验,后续的文章中我会给大家逐步讲解token加密与cookie的解析等等(其实很简单)

NoteService接口的实现类

新建NoteServiceImpl类实现NoteService接口

//此类与controller层直接交互,进行逻辑处理
@Service
@Slf4j
public class NoteServiceImpl implements NoteService {


    @Autowired
    private NoteRepository noteRepository;

    @Autowired
    private IUserRedisService userRedisService;

    @Autowired
    private UserRepository userRepository;


    /**
     * 获取日记
     *
     * @param pageable
     * @return
     * @throws Exception
     */
    @Override
    public Page<NoteInfoVO> noteList(HttpServletRequest request, Pageable pageable) throws Exception {
        //判断用户是否存在
        checkUser(getUserId(request));

        //判断用户token
        checkToken(getToken(request), getUserId(request));

        Page<NoteInfoEntity> noteInfoPage = noteRepository.findByUserIdOrderByUpdateTimeDesc(getUserId(request), pageable);

        List<NoteInfoVO> noteInfoVOList = NoteEntity2NoteDTOConverter.convert(noteInfoPage.getContent());

        return new PageImpl<>(noteInfoVOList, pageable, noteInfoPage.getTotalElements());
    }

    /**
     * 更新日记
     *
     * @param request
     * @param userNoteDTO
     * @return
     * @throws Exception
     */
    @Override
    public NoteInfoVO updateNote(HttpServletRequest request, UserNoteDTO userNoteDTO) throws Exception {

        //判断用户是否存在
        checkUser(getUserId(request));

        //标题必传
        if (StringUtils.isEmpty(userNoteDTO.getNoteTitle())) {
            throw new NoteException(ResultEnum.NOTE_TITLE_NON_ERROR);
        }

        //内容必传
        if (StringUtils.isEmpty(userNoteDTO.getNoteTitle())) {
            throw new NoteException(ResultEnum.NOTE_CONTENT_NON_ERROR);
        }

        //noteId必传
        if (StringUtils.isEmpty(userNoteDTO.getNoteId()) || userNoteDTO.getNoteId() == 0) {
            throw new NoteException(ResultEnum.NOTE_ID_NON_ERROR);
        }

        //判断用户token
        checkToken(getToken(request), getUserId(request));

        NoteInfoEntity newInfoEntity = new NoteInfoEntity();
        Util.copyPropertiesIgnoreNull(userNoteDTO, newInfoEntity);

        NoteInfoEntity infoEntity = noteRepository.save(newInfoEntity);

        //数据转换
        NoteInfoVO infoDTO = new NoteInfoVO();
        Util.copyPropertiesIgnoreNull(infoEntity, infoDTO);

        log.error("这是NoteInfoEntity=>", infoEntity);
        log.error("NoteInfoVO=>", infoDTO);


        return infoDTO;
    }

    /**
     * 添加日记
     *
     * @param request
     * @param userNoteDTO
     * @return
     * @throws Exception
     */
    @Override
    public NoteInfoVO addNote(HttpServletRequest request, UserNoteDTO userNoteDTO) throws Exception {

        //判断用户是否存在
        checkUser(getUserId(request));

        //标题必传
        if (StringUtils.isEmpty(userNoteDTO.getNoteTitle())) {
            throw new NoteException(ResultEnum.NOTE_TITLE_NON_ERROR);
        }

        //内容必传
        if (StringUtils.isEmpty(userNoteDTO.getNoteTitle())) {
            throw new NoteException(ResultEnum.NOTE_CONTENT_NON_ERROR);
        }

        //判断用户token
        checkToken(getToken(request), getUserId(request));

        NoteInfoEntity newInfoEntity = noteRepository.findOne(userNoteDTO.getNoteId());

        Util.copyPropertiesIgnoreNull(userNoteDTO, newInfoEntity);

        NoteInfoEntity infoEntity = noteRepository.save(newInfoEntity);

        //数据转换
        NoteInfoVO infoDTO = new NoteInfoVO();
        Util.copyPropertiesIgnoreNull(infoEntity, infoDTO);

        log.error("这是NoteInfoEntity=>", infoEntity);
        log.error("NoteInfoVO=>", infoDTO);


        return infoDTO;
    }

    /**
     * 删除日记
     *
     * @param request
     * @param userNoteDTO
     * @throws Exception
     */
    @Override
    public void delNote(HttpServletRequest request, UserNoteDTO userNoteDTO) throws Exception {

        //判断用户是否存在
        checkUser(getUserId(request));

        //noteId必传
        if (StringUtils.isEmpty(userNoteDTO.getNoteId()) || userNoteDTO.getNoteId() == 0) {
            throw new NoteException(ResultEnum.NOTE_ID_NON_ERROR);
        }

        //判断用户token
        checkToken(getToken(request), getUserId(request));

        noteRepository.delete(userNoteDTO.getNoteId());
    }


    /**
     * 判断用户token
     *
     * @throws Exception
     */
    private void checkToken(String token, String userId) throws Exception {

        Util.checkToken(token, userId, userRedisService);
    }

    /**
     * 获取Token
     *
     * @param request
     * @return
     */
    private String getToken(HttpServletRequest request) {
        Cookie cookie = CookieUtil.getCookieByName(request, "token");
        //token必传
        if (null == cookie) {
            throw new NoteException(ResultEnum.TOKEN_NON_ERROR);
        }
        return cookie.getValue();
    }

    /**
     * 获取userId
     *
     * @param request
     * @return
     */
    private String getUserId(HttpServletRequest request) {
        Cookie cookie = CookieUtil.getCookieByName(request, "userId");
        //userId必传
        if (null == cookie) {
            throw new NoteException(ResultEnum.USERID_NON_ERROR);
        }
        return cookie.getValue();
    }


    /**
     * 判断用户是否存在
     *
     * @param userId
     * @return
     */
    private void checkUser(String userId) {
        if (userRepository.findOne(userId) == null) {
            throw new NoteException(ResultEnum.USER_NOT_EXIST);
        }
    }
}

UserService接口的实现类

新建UserServiceImpl类实现UserService接口

//此类与controller层直接交互,进行逻辑处理
@Service
public class UserServiceImpl implements UserService {

    @Autowired
    private UserRepository userRepository;

    @Autowired
    private IUserRedisService userRedisService;


    /**
     * 用户注册
     *
     * @param userInfoEntity
     * @return
     * @throws Exception
     */
    @Override
    public UserInfoVO userRegister(UserInfoEntity userInfoEntity) throws Exception {

        //用户id必传
        if (StringUtils.isEmpty(userInfoEntity.getUserId())) {
            throw new NoteException(ResultEnum.USERID_NON_ERROR);
        }

        //用户密码必传
        if (StringUtils.isEmpty(userInfoEntity.getUserPwd())) {
            throw new NoteException(ResultEnum.PASSWORD_NON_ERROR);
        }
        //用户名必传
        if (StringUtils.isEmpty(userInfoEntity.getUserName())) {
            throw new NoteException(ResultEnum.USERNAME_NON_ERROR);
        }

        if (null != userRepository.findOne(userInfoEntity.getUserId())) {
            throw new NoteException(ResultEnum.REGISTER_ERROR_HAD);
        }

        UserInfoVO result = new UserInfoVO();
        //获取请求对象
        UserInfoEntity infoEntity = userRepository.save(userInfoEntity);
        // 对象转换
        BeanUtils.copyProperties(infoEntity, result);

        return result;
    }

    /**
     * 用户登录
     *
     * @param loginEntity
     * @param servletResponse
     * @return
     * @throws Exception
     */
    @Override
    public UserInfoVO userLogin(UserLoginEntity loginEntity, HttpServletResponse servletResponse) throws Exception {

        //用户id必传
        if (StringUtils.isEmpty(loginEntity.getUserId())) {
            throw new NoteException(ResultEnum.USERID_NON_ERROR);
        }

        //用户密码必传
        if (StringUtils.isEmpty(loginEntity.getUserPwd())) {
            throw new NoteException(ResultEnum.PASSWORD_NON_ERROR);
        }

        // 获取UserInfo对象
        UserInfoEntity infoEntity = getUserInfo(loginEntity.getUserId());
        if (!infoEntity.getUserPwd().equals(loginEntity.getUserPwd())) {
            throw new NoteException(ResultEnum.LOGIN_ERROR);
        }

        //生成token
        Map<String, Object> map = new HashMap<>();
        map.put("id", infoEntity.getUserId());
        map.put("date", System.currentTimeMillis());
        map.put("name", infoEntity.getUserName());
        String token = SecurityUtil.authentication(map);

        //保存用户token到redis
        userRedisService.saveToken(infoEntity.getUserId(), token);

        UserInfoVO userInfoVO = new UserInfoVO();
        BeanUtils.copyProperties(infoEntity, userInfoVO);
        CookieUtil.addCookie(servletResponse, "token", token, 10);

        return userInfoVO;
    }

    /**
     * 修改密码
     *
     * @param request
     * @param userInfoDTO
     * @throws Exception
     */
    @Override
    public void updatePwd(HttpServletRequest request, UserInfoDTO userInfoDTO) throws Exception {

        //判断用户是否存在
        checkUser(getUserId(request));

        //用户密码必传
        if (StringUtils.isEmpty(userInfoDTO.getOldPwd())) {
            throw new NoteException(ResultEnum.PASSWORD_NON_ERROR);
        }

        //用户新密码必传
        if (StringUtils.isEmpty(userInfoDTO.getNewPwd())) {
            throw new NoteException(ResultEnum.PASSWORD_NEW_NON_ERROR);
        }

        //校验token
        checkToken(getToken(request), getUserId(request));

        //校验旧密码
        UserInfoEntity infoEntity = getUserInfo(userInfoDTO.getUserId());
        if (!userInfoDTO.getOldPwd().equals(infoEntity.getUserPwd())) {
            throw new NoteException(ResultEnum.PASSWORD_CHECK_ERROR);
        }

        //设置新密码
        infoEntity.setUserPwd(userInfoDTO.getNewPwd());

        userRepository.save(infoEntity);
    }

    /**
     * 更新个人资料
     *
     * @param request
     * @param userInfoDTO
     * @throws Exception
     */
    @Override
    public void updateProfile(HttpServletRequest request, UserInfoDTO userInfoDTO) throws Exception {

        //判断用户是否存在
        checkUser(getUserId(request));

        //个人简介必传
        if (StringUtils.isEmpty(userInfoDTO.getUserProfile())) {
            throw new NoteException(ResultEnum.PROFILE_NON_ERROR);
        }

        // 校验token
        checkToken(getToken(request), getUserId(request));

        //修改profile
        UserInfoEntity infoEntity = getUserInfo(userInfoDTO.getUserId());
        infoEntity.setUserProfile(userInfoDTO.getUserProfile());

        //修改数据库
        userRepository.save(infoEntity);
    }

    /**
     * 获取用户信息
     *
     * @param request
     * @return
     * @throws Exception
     */
    @Override
    public UserInfoVO userInfo(HttpServletRequest request) throws Exception {

        //判断用户是否存在
        checkUser(getUserId(request));

        // 校验token
        checkToken(getToken(request), getUserId(request));

        //获取用户信息
        UserInfoEntity infoEntity = getUserInfo(getUserId(request));

        UserInfoVO vo = new UserInfoVO();

        //拷贝数据
        BeanUtils.copyProperties(infoEntity, vo);

        return vo;
    }

    /**
     * 退出,清除token
     *
     * @param request
     * @throws Exception
     */
    @Override
    public void userLogout(HttpServletRequest request) throws Exception {
        userRedisService.removeToken(getUserId(request));
    }


    /**
     * 判断用户token
     *
     * @param token
     * @param userId
     * @throws Exception
     */
    private void checkToken(String token, String userId) throws Exception {
        Util.checkToken(token, userRedisService.getToken(userId));
    }

    /**
     * 获取UserInfo实体
     *
     * @param userId
     * @return
     */
    private UserInfoEntity getUserInfo(String userId) {
        return userRepository.findOne(userId);
    }


    /**
     * 获取Token
     *
     * @param request
     * @return
     */
    private String getToken(HttpServletRequest request) {
        Cookie cookie = CookieUtil.getCookieByName(request, "token");
        //token必传
        if (null == cookie) {
            throw new NoteException(ResultEnum.TOKEN_NON_ERROR);
        }
        return cookie.getValue();
    }

    /**
     * 获取userId
     *
     * @param request
     * @return
     */
    private String getUserId(HttpServletRequest request) {
        Cookie cookie = CookieUtil.getCookieByName(request, "userId");
        //userId必传
        if (null == cookie) {
            throw new NoteException(ResultEnum.USERID_NON_ERROR);
        }
        return cookie.getValue();
    }


    /**
     * 判断用户是否存在
     *
     * @param userId
     * @return
     */
    private void checkUser(String userId) {
        if (userRepository.findOne(userId) == null) {
            throw new NoteException(ResultEnum.USER_NOT_EXIST);
        }
    }

}

这两个类中用到了一些token的校验、redis的获取等等,不懂的地方大家不要慌。相关知识在后续的文章中会为大家一一讲解,在这里入门的童鞋们还是先做个大致的了解,等看完该系列所有文章后一定会让你彻底理解。

本篇文章到此就结束了,在下一章的内容中我将会为大家介绍利用Exception来处理全局的错误代码以及系统异常。


项目地址

本项目的完整项目代码的github地址

https://github.com/BigWolfDean/springboot-simple-project

如果本项目对大家有一些帮助的话,麻烦给个star,fork一下,谢谢!


本系列文章目录

SpringBoot入门项目-基于JPA的App日记后台系统之项目的搭建与配置(一)

SpringBoot入门项目-SpringBoot入门项目-基于JPA的App日记后台系统之数据库的创建与JPA的CRUD(二)

SpringBoot入门项目-基于JPA的App日记后台系统之利用Exception处理自定义错误信息(三)

SpringBoot入门项目-SpringBoot入门项目-基于JPA的App日记后台系统之Controller层的编写(四)

SpringBoot入门项目-基于JPA的App日记后台系统之利用Redis与Cookie处理用户权限校验(五)

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值