系列大纲 |
GitHub(还没开发完成) |
在线演示www.yzpnb.top |
第一章:(后端)搭建spring boot脚手架:https://blog.csdn.net/grd_java/article/details/107452826 |
第二章:权限整合shiro+jwt,完成后端接口:https://blog.csdn.net/grd_java/article/details/107481570 |
第三章:搭建前端vue整合element ui脚手架:https://blog.csdn.net/grd_java/article/details/107498140 |
第四章:首页和公共头部组件:https://blog.csdn.net/grd_java/article/details/107507213 |
第五章:完成登陆注册页面,nginx网关对接后端:https://blog.csdn.net/grd_java/article/details/107515437 |
第六章:博客页面,观看博客,博客编辑功能:https://blog.csdn.net/grd_java/article/details/107525128 |
第七章:打包部署,多节点部署方案:https://blog.csdn.net/grd_java/article/details/107533253 |
在b站发现了一个不错的前后端分离博客项目 |
原本我是想整合spring security来做权限,手写一套响应式前端。但是最近学校要求我去整合项目 |
所以我前往b站找了找现成的,但是教学视频大多数为了让观众容易理解,将大部分分布式和扩展性内容极简化 |
我决定找一个相对简单的,但是所有的都是用的shiro做权限,所以我这里就先把shiro整合到分布式项目 |
这个项目我整合到了脚手架,有了充分的扩展性,大家可以跟着把这个做完部署到服务器 |
之后我将学校的任务完成后,会将shiro换成spring security,然后将页面和功能重写 |
到时候,我会用sass做css的模块化,并自己封装一套vue组件库来搭建前端 |
以下是我找的开源博客项目,我仅仅使用了shiro代码,因为原视频中没有用到分布式的模块化 |
我在b站找的视频链接:https://www.bilibili.com/video/BV1PQ4y1P7hZ |
相应博客链接:https://juejin.im/post/5ecfca676fb9a04793456fb8#heading-6 |
文章目录
- 一、整合shiro+jwt
-
- 1、创建通用模块,引入shiro和jwt依赖
- 2、配置shiro
-
- 1、JwtToken
- 2、JwtUtils
- 3、AccountProfile
- 4、AccountRealm
- 5、jwt过滤器
- 6、最终配置ShiroConfig
- 7、异常处理
- 8、测试
- 二、登陆接口
-
- 1、实体校验
- 2、登录实体类
- 3、添加数据库测试数据
- 4、登录Controller
- 5、测试
- 三、功能接口开发
-
- 1、注册用户
- 2、博客的增删改查
- 3、测试
- 4、补充知识
一、整合shiro+jwt
如果你不想整合shiro做权限控制,直接跳到登陆接口开发就可以了,但是仅仅是拷贝代码就可以完成shiro的整合 |
1、创建通用模块,引入shiro和jwt依赖
<dependencies>
<!--shiro redis spring boot 整合包,这个包整合了3个-->
<dependency>
<groupId>org.crazycake</groupId>
<artifactId>shiro-redis-spring-boot-starter</artifactId>
<version>3.2.1</version>
</dependency>
<!-- hutool工具类-->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.3.3</version>
</dependency>
<!-- jwt -->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
</dependencies>
2、配置shiro
1、JwtToken
package com.yzpnb.shiro.handler;
import org.apache.shiro.authc.AuthenticationToken;
public class JwtToken implements AuthenticationToken {
private String token;
public JwtToken(String token) {
this.token = token;
}
@Override
public Object getPrincipal() {
return token;
}
@Override
public Object getCredentials() {
return token;
}
}
2、JwtUtils
shiro-redis:
enabled: true
redis-manager:
host: 127.0.0.1:6379
yzpnb:
jwt:
secret: f4e2e52034348f86b67cde581c0f9eb5
expire: 604800
header: token
package com.yzpnb.shiro.utils;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import java.util.Date;
@Component
@ConfigurationProperties(prefix = "yzpnb.jwt")
public class JwtUtils {
private String secret;
private long expire;
private String header;
public String generateToken(String userId) {
Date nowDate = new Date();
Date expireDate = new Date(nowDate.getTime()+expire * 1000);
return Jwts.builder()
.setHeaderParam("typ","JWT")
.setSubject(userId)
.setIssuedAt(nowDate)
.setExpiration(expireDate)
.signWith(SignatureAlgorithm.HS512,secret)
.compact();
}
public Claims getClaimByToken(String token) {
try{
return Jwts.parser()
.setSigningKey(secret)
.parseClaimsJws(token)
.getBody();
}catch(Exception e){
return null;
}
}
public boolean isTokenExpired(Date expiration) {
return expiration.before(new Date());
}
}
3、AccountProfile
package com.yzpnb.shiro.handler;
import lombok.Data;
import java.io.Serializable;
@Data
public class AccountProfile implements Serializable {
private Long id;
private String username;
private String avatar;
}
4、AccountRealm
package com.yzpnb.shiro.handler;
import com.yzpnb.shiro.utils.JwtUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Slf4j
@Component
public class AccountRealm extends AuthorizingRealm {
@Autowired
JwtUtils jwtUtils;
@Override
public boolean supports(AuthenticationToken token) {
return token instanceof JwtToken;
}
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
return null;
}
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
return null;
}
}
package com.yzpnb.service_blog.shiro;
import cn.hutool.core.bean.BeanUtil;
import com.yzpnb.service_blog.entity.MUser;
import com.yzpnb.service_blog.service.MUserService;
import com.yzpnb.shiro.handler.AccountProfile;
import com.yzpnb.shiro.handler.AccountRealm;
import com.yzpnb.shiro.handler.JwtToken;
import com.yzpnb.shiro.utils.JwtUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.authc.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Slf4j
@Component
public class ServiceAccountRealm extends AccountRealm {
@Autowired
JwtUtils jwtUtils;
@Autowired
MUserService mUserService;
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
JwtToken jwt = (JwtToken) token;
log.info("jwt----------------->{}", jwt);
String userId = jwtUtils.getClaimByToken((String) jwt.getPrincipal()).getSubject();
MUser mUser = mUserService.getById(Long.parseLong(userId));
if(mUser == null) {
throw new UnknownAccountException("账户不存在!");
}
if(mUser.getStatus() == -1) {
throw new LockedAccountException("账户已被锁定!");
}
AccountProfile profile = new AccountProfile();
BeanUtil.copyProperties(mUser, profile);
log.info("profile----------------->{}", profile.toString());
return new SimpleAuthenticationInfo(profile, jwt.getCredentials(), getName());
}
}
5、jwt过滤器
package com.yzpnb.shiro.filter;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.yzpnb.common_utils.Result;
import com.yzpnb.shiro.handler.JwtToken;
import com.yzpnb.shiro.utils.JwtUtils;
import io.jsonwebtoken.Claims;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.ExpiredCredentialsException;
import org.apache.shiro.web.filter.authc.AuthenticatingFilter;
import org.apache.shiro.web.util.WebUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RequestMethod;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@Component
public class JwtFilter extends AuthenticatingFilter {
@Autowired
JwtUtils jwtUtils;
@Override
protected AuthenticationToken createToken(ServletRequest servletRequest, ServletResponse servletResponse) throws Exception {
HttpServletRequest request = (HttpServletRequest) servletRequest;
String jwt = request.getHeader("Authorization");
if(StringUtils.isEmpty(jwt)){
return null;
}
return new JwtToken(jwt);
}
@Override
protected boolean onAccessDenied(ServletRequest servletRequest, ServletResponse servletResponse) throws Exception {
HttpServletRequest request = (HttpServletRequest) servletRequest;
String token = request.getHeader("Authorization");
if(StringUtils.isEmpty(token)) {
return true;
} else {
Claims claim = jwtUtils.getClaimByToken(token);
if(claim == null || jwtUtils.isTokenExpired(claim.getExpiration())) {
throw new ExpiredCredentialsException("token已失效,请重新登录!");
}
}
return executeLogin(servletRequest, servletResponse);
}
@Override
protected boolean onLoginFailure(AuthenticationToken token, AuthenticationException e, ServletRequest request, ServletResponse response) {
HttpServletResponse httpResponse = (HttpServletResponse) response;
try {
Throwable throwable = e.getCause() == null ? e : e.getCause();
Result r = Result.error().message(throwable.getMessage());
String json = JSONUtil.toJsonStr(r);
httpResponse.getWriter().print(json);
} catch (IOException e1) {
}
return false;
}
@Override
protected boolean preHandle(ServletRequest request, ServletResponse response) throws Exception {
HttpServletRequest httpServletRequest = WebUtils.toHttp(request);
HttpServletResponse httpServletResponse = WebUtils.toHttp(response);
httpServletResponse.setHeader("Access-control-Allow-Origin", httpServletRequest.getHeader("Origin"));
httpServletResponse.setHeader("Access-Control-Allow-Methods", "GET,POST,OPTIONS,PUT,DELETE");
httpServletResponse.setHeader("Access-Control-Allow-Headers", httpServletRequest.getHeader("Access-Control-Request-Headers"));
if (httpServletRequest.getMethod().equals(RequestMethod.OPTIONS.name())) {
httpServletResponse.setStatus(org.springframework.http.HttpStatus.OK.value());
return false;
}
return super.preHandle(request, response);
}
}
6、最终配置ShiroConfig
package com.yzpnb.shiro.config;
import com.yzpnb.shiro.filter.JwtFilter;
import com.yzpnb.shiro.handler.AccountRealm;
import org.apache.shiro.mgt.DefaultSessionStorageEvaluator;
import org.apache.shiro.mgt.DefaultSubjectDAO;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.session.mgt.SessionManager;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.spring.web.config.DefaultShiroFilterChainDefinition;
import org.apache.shiro.spring.web.config.ShiroFilterChainDefinition;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.crazycake.shiro.RedisCacheManager;
import org.crazycake.shiro.RedisSessionDAO;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.servlet.Filter;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
@Configuration
public class ShiroConfigura {
@Autowired
private JwtFilter jwtFilter;
@Bean
public SessionManager sessionManager(RedisSessionDAO redisSessionDAO) {
DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
sessionManager.setSessionDAO(redisSessionDAO);
return sessionManager;
}
@Bean
public DefaultWebSecurityManager securityManager(AccountRealm accountRealm,
SessionManager sessionManager,
RedisCacheManager redisCacheManager) {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(accountRealm);
securityManager.setSessionManager(sessionManager);
securityManager.setCacheManager(redisCacheManager);
DefaultSubjectDAO subjectDAO = new DefaultSubjectDAO();
DefaultSessionStorageEvaluator defaultSessionStorageEvaluator = new DefaultSessionStorageEvaluator();
defaultSessionStorageEvaluator.setSessionStorageEnabled(false);
subjectDAO.setSessionStorageEvaluator(defaultSessionStorageEvaluator);
securityManager.setSubjectDAO(subjectDAO);
return securityManager;
}
@Bean
public ShiroFilterChainDefinition shiroFilterChainDefinition() {
DefaultShiroFilterChainDefinition chainDefinition = new DefaultShiroFilterChainDefinition();
Map<String, String> filterMap = new LinkedHashMap<>();
filterMap.put("/**", "jwt");
chainDefinition.addPathDefinitions(filterMap);
return chainDefinition;
}
@Bean("shiroFilterFactoryBean")
public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager,
ShiroFilterChainDefinition shiroFilterChainDefinition) {
ShiroFilterFactoryBean shiroFilter = new ShiroFilterFactoryBean();
shiroFilter.setSecurityManager(securityManager);
Map<String, Filter> filters = new HashMap<>();
filters.put("jwt", jwtFilter);
shiroFilter.setFilters(filters);
Map<String, String> filterMap = shiroFilterChainDefinition.getFilterChainMap();
shiroFilter.setFilterChainDefinitionMap(filterMap);
return shiroFilter;
}
// 开启注解代理(默认好像已经开启,可以不要)
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager){
AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
return authorizationAttributeSourceAdvisor;
}
@Bean
public static DefaultAdvisorAutoProxyCreator getDefaultAdvisorAutoProxyCreator() {
DefaultAdvisorAutoProxyCreator creator = new DefaultAdvisorAutoProxyCreator();
return creator;
}
}
7、异常处理
package com.yzpnb.shiro.handler;
import com.yzpnb.common_utils.Result;
import com.yzpnb.service_base.handler.MyExceptionHandler;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.ShiroException;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.validation.BindingResult;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import java.io.IOException;
@Slf4j
@Component
public class ShiroExceptionHandler extends MyExceptionHandler {
@ResponseBody
@ExceptionHandler(ShiroException.class)
public Result handle401(org.apache.shiro.ShiroException e) {
return Result.error().code(401).message("你好"+e.getMessage());
}
@ResponseBody
@ExceptionHandler(value = IllegalArgumentException.class)
public Result handler(IllegalArgumentException e) throws IOException {
return Result.error().message(e.getMessage());
}
@ResponseBody
@ExceptionHandler(value = MethodArgumentNotValidException.class)
public Result handler(MethodArgumentNotValidException e) throws IOException {
BindingResult bindingResult = e.getBindingResult();
ObjectError objectError = bindingResult.getAllErrors().stream().findFirst().get();
return Result.error().message(objectError.getDefaultMessage());
}
@ResponseBody
@ExceptionHandler(value = RuntimeException.class)
public Result handler(RuntimeException e) throws IOException {
return Result.error().message(e.getMessage());
}
}
8、测试
到这里,shiro就整合的差不多了,这里就充分体现了分布式模块化的优势 |
首先,按照我这样的配置,你在以后添加微服务时,只需要在相应的微服务中写一个继承AccountRealm的实现类即可实现shiro的复用 |
就是我们上面配置的第4步AccountRealm,当然,如果不需要登录,那这步都可以省略 |
和单体应用的配置量相同,仅仅包的结构复杂一点不好理解,但是大大增加项目的弹性 |
二、登陆接口
1、实体校验
登陆的时候肯定需要用到表单 |
这时我们需要进行一些逻辑判断,比如用户名不能为空 |
package com.yzpnb.service_blog.entity;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.IdType;
import java.util.Date;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import java.io.Serializable;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
import javax.validation.constraints.Email;
import javax.validation.constraints.NotBlank;
@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
@ApiModel(value="MUser对象", description="")
public class MUser implements Serializable {
private static final long serialVersionUID=1L;
@ApiModelProperty(value = "用户id")
@TableId(value = "id", type = IdType.ID_WORKER_STR)
private String id;
@NotBlank(message = "用户名不能为空")
@ApiModelProperty(value = "用户名")
private String username;
@ApiModelProperty(value = "头像")
private String avatar;
@NotBlank(message = "邮箱不能为空")
@Email(message = "邮箱格式不正确")
@ApiModelProperty(value = "邮箱")
private String email;
@NotBlank(message = "密码不能为空")
@ApiModelProperty(value = "密码")
private String password;
@ApiModelProperty(value = "状态")
private Integer status;
@ApiModelProperty(value = "创建时间")
@TableField(fill = FieldFill.INSERT)
private Date gmtCreated;
@ApiModelProperty(value = "更新时间")
@TableField(fill = FieldFill.INSERT_UPDATE)
private Date gmtModified;
@ApiModelProperty(value = "逻辑删除1删除,0未删除")
private Boolean isDelete;
}
controller接口 |
我们通过@Validated注解监听 |
如果不符合就报MethodArgumentNotValidException |
@RequestBody注解用来将前端传来的json封装到实体类 |
@PostMapping("login")
public Result login(@Validated @RequestBody MUser user){
return Result.ok().data("user",user);
}
处理相应异常 |
刚刚的shiro异常处理中我就把这个异常放进去了,放在service_base中,感觉不符合,所以和shiro异常放一起吧 |
2、登录实体类
对于这些只需要一两个属性的,就定义一个专属的实体类就好了 |
package com.yzpnb.service_blog.entity.md;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.NotBlank;
import java.io.Serializable;
@Data
public class LoginMD implements Serializable {
@NotBlank(message = "用户名不能为空")
@ApiModelProperty(value = "用户名")
private String username;
@NotBlank(message = "密码不能为空")
@ApiModelProperty(value = "密码")
private String password;
}
3、添加数据库测试数据
因为只有登录,还没有注册,所以先存一条数据 |
因为我们使用md5加密,所以对比时,要保证数据库中存储的都是加密后的密码 |
96e79218965eb72c92a549dd5a330112 |
上面这一串表示111111的md5加密格式 |
4、登录Controller
package com.yzpnb.service_blog.controller;
import cn.hutool.core.map.MapUtil;
import cn.hutool.crypto.SecureUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.yzpnb.common_utils.Result;
import com.yzpnb.service_blog.entity.MUser;
import com.yzpnb.service_blog.entity.md.LoginMD;
import com.yzpnb.service_blog.service.MUserService;
import com.yzpnb.shiro.utils.JwtUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authz.annotation.RequiresAuthentication;
import org.apache.shiro.util.Assert;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletResponse;
@RestController
@RequestMapping("/service_blog/account")
public class AccountController {
@Autowired
JwtUtils jwtUtils;
@Autowired
private MUserService userService;
@CrossOrigin
@PostMapping("/login")
public Result login(@Validated @RequestBody LoginMD loginMD, HttpServletResponse response) {
MUser user = userService.getOne(new QueryWrapper<MUser>().eq("username", loginMD.getUsername()));
Assert.notNull(user, "用户不存在");
if(!user.getPassword().equals(SecureUtil.md5(loginMD.getPassword()))) {
return Result.error().message("密码错误!");
}
String jwt = jwtUtils.generateToken(user.getId());
System.out.println("11");
response.setHeader("Authorization", jwt);
response.setHeader("Access-Control-Expose-Headers", "Authorization");
return Result.ok().data("loginMD",MapUtil.builder()
.put("id", user.getId())
.put("username", user.getUsername())
.put("avatar", user.getAvatar())
.put("email", user.getEmail())
.map()
);
}
@GetMapping("/logout")
public Result logout() {
SecurityUtils.getSubject().logout();
return Result.ok();
}
}
5、测试
三、功能接口开发
1、注册用户
package com.yzpnb.service_blog.entity.md;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.Email;
import javax.validation.constraints.NotBlank;
import java.io.Serializable;
@Data
public class SingInMD implements Serializable {
@NotBlank(message = "用户名不能为空")
@ApiModelProperty(value = "用户名")
private String username;
@NotBlank(message = "邮箱不能为空")
@Email(message = "邮箱格式不正确")
@ApiModelProperty(value = "邮箱")
private String email;
@NotBlank(message = "密码不能为空")
@ApiModelProperty(value = "密码")
private String password;
}
controller,我这里为了节省篇幅,就不把逻辑代码放在service中了,全写在controller中,维护会增加难度,所以你应该将逻辑放在service中 |
@PostMapping("signIn")
public Result sigIn(@Validated @RequestBody SingInMD singInMD){
MUser username = userService.getOne(new QueryWrapper<MUser>().eq("username", singInMD.getUsername()));
if(!StringUtils.isEmpty(username)){
throw new CustomExceptionHandler(20001,"用户名已注册");
}else{
username = userService.getOne(new QueryWrapper<MUser>().eq("email", singInMD.getEmail()));
if(!StringUtils.isEmpty(username)){
throw new CustomExceptionHandler(20001,"该邮箱已注册");
}
}
MUser user=new MUser();
BeanUtils.copyProperties(singInMD,user);
user.setPassword(SecureUtil.md5(singInMD.getPassword()));
user.setStatus(1);
user.setIsDelete(false);
boolean save = userService.save(user);
if(save){
return Result.ok();
}
throw new CustomExceptionHandler(20001,"注册失败");
}
可以看到id由mybatis plus自动生成了,自动填充了创建时间和修改时间 |
对应用户的先开发到这,日后在完善 |
2、博客的增删改查
package com.yzpnb.service_blog.entity.md;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.NotBlank;
import java.io.Serializable;
@Data
public class InsertBlog implements Serializable {
@ApiModelProperty(value = "用户id")
private String userId;
@NotBlank(message = "标题不能为空")
@ApiModelProperty(value = "博客标题")
private String title;
@ApiModelProperty(value = "简介内容")
private String description;
@NotBlank(message = "内容不能为空")
@ApiModelProperty(value = "内容")
private String content;
@ApiModelProperty(value = "发布状态")
private Integer status;
}
package com.yzpnb.service_blog.controller;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.yzpnb.common_utils.Result;
import com.yzpnb.service_base.handler.CustomExceptionHandler;
import com.yzpnb.service_blog.entity.MBlog;
import com.yzpnb.service_blog.entity.md.InsertBlog;
import com.yzpnb.service_blog.service.MBlogService;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.apache.ibatis.annotations.Delete;
import org.apache.shiro.authz.annotation.RequiresAuthentication;
import org.apache.shiro.util.Assert;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/service_blog/m-blog")
public class MBlogController {
@Autowired
private MBlogService blogService;
@ApiOperation(value="分页查询所有博客")
@GetMapping("limitSelect/{current}/{size}")
public Result limitSelect(@ApiParam(name="current",value ="当前页",required=true)
@PathVariable("current") Long current,
@ApiParam(name="size",value="每页记录数")
@PathVariable("size") Long size){
Page<MBlog> page=new Page<>(current,size);
return Result.ok().data("limitBlog",blogService.page(page));
}
@ApiOperation("根据id获取博客")
@GetMapping("blogById/{id}")
public Result selectById(@ApiParam(name="id",value = "博客id")
@PathVariable(name = "id") Long id) {
MBlog blog = blogService.getById(id);
Assert.notNull(blog, "该博客已删除!");
return Result.ok().data("blog",blog);
}
@ApiOperation(value = "根据id修改博客")
@PutMapping("blogById")
public Result updataById( @ApiParam(name = "blog",value = "博客信息")
@Validated @RequestBody MBlog blog) {
boolean b = blogService.updateById(blog);
if(b){
return Result.ok().message("修改成功");
}
throw new CustomExceptionHandler(20001,"修改失败");
}
@ApiOperation("根据id删除博客")
@DeleteMapping("blogById/{id}")
public Result deleteById( @ApiParam(name = "id",value = "博客id")
@PathVariable String id) {
boolean b = blogService.removeById(id);
if(b){
return Result.ok().message("删除成功");
}
throw new CustomExceptionHandler(20001,"删除失败");
}
@ApiOperation("添加博客")
@PostMapping("insertBlog")
public Result insertBlog( @ApiParam(name = "blog",value = "博客信息")
@Validated @RequestBody InsertBlog blog) {
MBlog mBlog=new MBlog();
BeanUtils.copyProperties(blog,mBlog);
mBlog.setStatus(0);
mBlog.setIsDelete(false);
boolean b = blogService.save(mBlog);
if(b){
return Result.ok().message("保存成功");
}
throw new CustomExceptionHandler(20001,"保存失败");
}
}
3、测试
到此后端的基本功能模块就开发完成了,接下来就可以进入到前端的开发了 |
因为这里分布式模块化做的比较完善,之后添加功能也十分方便 |
4、补充知识
数据库中存储的时间,没有办法直接使用,添加一个注解即可 |
@JsonFormat(pattern = “yyyy-MM-dd HH:mm”)//将获取的时间格式化 |