提要 本系列文章主要为带领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
目录
- 提要
- 目录
- 数据库的配置
- 数据库的创建
- 数据库表的建立
- UserInfoEntity类
- NoteInfoEntity类
- 注解说明
- JPA中Repository接口说明
-
- JpaRepository接口
- NoteRepository接口
- UserRepository接口
-
- 新建Service进行CRUD操作
-
- NoteService接口
- UserService接口
- NoteService接口的实现类
- UserService接口的实现类
-
- 项目地址
- 本系列文章目录
数据库的配置 数据库的创建 在上一章节的文章中我有提到本项目中所使用的数据库为MySQL,数据库的图形化管理软件我个人推荐使用Navicat。
现在我们来回顾一下上一章所提到的application.yml文件中MySQL数据库的配置信息。
spring:
datasource:
url: jdbc:mysql://127.0.0.1/test0110?characterEncoding=utf-8&useSSL=false
username: root
password: 123456
【Java|SpringBoot入门项目-基于JPA的App日记后台系统之数据库的创建与JPA的CRUD(二)】我们之前也提到了url中的test0110为数据库的名称,所以我们在运行项目之前必须先创建数据库,否则运行会直接报错!
下面我们将通过Navicat这个软件来新建数据库。
文章图片
我们通过选中本地/远程的数据库,右键选择新建数据库。
文章图片
根据图中所填写的信息进行填写,数据库名可根据个人喜好自行更改。(注意,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 注解表示指定当前的类与数据库中的表进行映射,一个类对应一张表,一个变量对应一个字段。通过上一章节所提到的application.yml文件中的片段
@Table 注解表示指定当前类对应的表名。
@DynamicUpdate 注解表示当前类中的Date属性会动态更新。
@Data 注解为lombok中的注解,表示自动为你生成get/set方法,让你的代码更加整洁。
@Id 代表为主键。
@GeneratedValue 代表为自增。
@UpdateTimestamp 指示其自动更新。
数据库说明:
Data类中的变量名与数据库中字段名对应规则举栗:userName -> user_name
jpa:
hibernate:
ddl-auto: update
可实现运行项目后根据标注了@Entity注解的类进行表与字段的更新,如数据库中无对应的表,则会自动创建。
JPA中Repository接口说明 数据库的表与字段都已经创建完毕了,接下来我们该干什么呢?没错,接下来我们将要对数据库进行增删查改相关操作。
我们先创建repository包,在repository包下分别创建NoteRepository接口和UserRepository接口,两个接口都需继承JpaRepository接口,让我们来先看一下JpaRepository接口里是什么内容。
JpaRepository接口
@NoRepositoryBean
public interface JpaRepository extends PagingAndSortingRepository, QueryByExampleExecutor {
List findAll();
List findAll(Sort var1);
List findAll(Iterable var1);
List save(Iterable var1);
void flush();
S saveAndFlush(S var1);
void deleteInBatch(Iterable var1);
void deleteAllInBatch();
T getOne(ID var1);
List findAll(Example var1);
List findAll(Example var1, Sort var2);
}
我们可以看到JpaRepository接口又继承于PagingAndSortingRepository接口与QueryByExampleExecutor接口,其中PagingAndSortingRepository接口中包含了两个findAll()方法
//用于迭代
Iterable findAll(Sort var1);
//用于分页
Page findAll(Pageable var1);
其中返回类型为Page的我们项目后面会使用到,用于分页功能。Iterable在此不做讲解,如有兴趣的童鞋可自行查找相关资料。通过这里我们便可以知道jpa就是通过repository来对数据库进行CRUD操作的。
NoteRepository接口
//JpaRepository中包含两个输入参数,一个是泛型,对应指定的entity,一个是Id的类型
public interface NoteRepository extends JpaRepository {
//查找指定用户的日记列表,并根据更新时间倒序排序后以分页的形式进行获取
Page 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 {}
新建Service进行CRUD操作 到此我们的准备工作已经完毕,接下来便是本章内容的重头戏了!调用JpaRepository接口进行CRUD!小伙伴们是不是也很激动啊!?
先别激动,拿稳鼠标,放稳键盘,深呼吸一口!我们先新建一个service包,在service包下新建两个接口,NoteService接口和UserService接口。
NoteService接口
public interface NoteService {
//获取用户下的所有日记列表(分页获取)
Page 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 noteList(HttpServletRequest request, Pageable pageable) throws Exception {
//判断用户是否存在
checkUser(getUserId(request));
//判断用户token
checkToken(getToken(request), getUserId(request));
Page noteInfoPage = noteRepository.findByUserIdOrderByUpdateTimeDesc(getUserId(request), pageable);
List 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 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处理用户权限校验(五)
推荐阅读
- CGB2202|CGB2202面向对象第7天
- CGB2202|CGB2202面向对象第8天
- 源码|第13期在线音乐网站前后分离springboot整合vue
- 源码|第11期学生住宿管理系统+程序设计文档
- 面试题|分布式事务面试题 (史上最全、持续更新、吐血推荐)
- 杂谈|eclipse使用小技巧
- 框架|用eclipse开发工具,maven进行包管理,整合SSH框架
- 2月券商App行情刷新及交易体验报告,东方与安信升至领导者象限
- 编程语言|程序员毕业两年,三年工作经验是怎么来的( | 每日趣闻)