From 18a8855edba9e6ca946e2d68ee8009900c98bd97 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E9=9B=B6=E8=90=BD=E6=98=9F=E6=B6=AF?= <781958167@qq.com>
Date: Thu, 14 May 2020 09:56:00 +0800
Subject: [PATCH] =?UTF-8?q?init=EF=BC=8C=E5=89=8D=E5=90=8E=E7=AB=AF?=
=?UTF-8?q?=E5=88=86=E7=A6=BB=E5=8D=9A=E5=AE=A2=E9=A1=B9=E7=9B=AE=E6=A1=88?=
=?UTF-8?q?=E4=BE=8B?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
README.md | 1 +
vueblog-java/.gitignore | 31 +++++
vueblog-java/pom.xml | 107 +++++++++++++++
.../main/java/com/markerhub/Application.java | 14 ++
.../java/com/markerhub/CodeGenerator.java | 116 ++++++++++++++++
.../com/markerhub/common/dto/LoginDto.java | 17 +++
.../exception/GlobalExcepitonHandler.java | 61 +++++++++
.../com/markerhub/common/lang/Result.java | 42 ++++++
.../java/com/markerhub/config/CorsConfig.java | 19 +++
.../markerhub/config/MybatisPlusConfig.java | 19 +++
.../com/markerhub/config/ShiroConfig.java | 110 ++++++++++++++++
.../controller/AccountController.java | 55 ++++++++
.../markerhub/controller/BlogController.java | 34 +++++
.../main/java/com/markerhub/entity/Blog.java | 42 ++++++
.../main/java/com/markerhub/entity/User.java | 49 +++++++
.../java/com/markerhub/mapper/BlogMapper.java | 16 +++
.../java/com/markerhub/mapper/UserMapper.java | 16 +++
.../com/markerhub/service/BlogService.java | 16 +++
.../com/markerhub/service/UserService.java | 16 +++
.../service/impl/BlogServiceImpl.java | 20 +++
.../service/impl/UserServiceImpl.java | 20 +++
.../com/markerhub/shiro/AccountProfile.java | 13 ++
.../com/markerhub/shiro/AccountRealm.java | 58 ++++++++
.../java/com/markerhub/shiro/JwtFilter.java | 103 +++++++++++++++
.../java/com/markerhub/shiro/JwtToken.java | 22 ++++
.../java/com/markerhub/util/JwtUtils.java | 62 +++++++++
.../com/markerhub/util/ValidationUtil.java | 124 ++++++++++++++++++
.../META-INF/spring-devtools.properties | 1 +
.../src/main/resources/application.yml | 22 ++++
.../src/main/resources/mapper/BlogMapper.xml | 5 +
.../src/main/resources/mapper/UserMapper.xml | 5 +
...tShiroMybatisplusDemoApplicationTests.java | 13 ++
32 files changed, 1249 insertions(+)
create mode 100644 README.md
create mode 100644 vueblog-java/.gitignore
create mode 100644 vueblog-java/pom.xml
create mode 100644 vueblog-java/src/main/java/com/markerhub/Application.java
create mode 100644 vueblog-java/src/main/java/com/markerhub/CodeGenerator.java
create mode 100644 vueblog-java/src/main/java/com/markerhub/common/dto/LoginDto.java
create mode 100644 vueblog-java/src/main/java/com/markerhub/common/exception/GlobalExcepitonHandler.java
create mode 100644 vueblog-java/src/main/java/com/markerhub/common/lang/Result.java
create mode 100644 vueblog-java/src/main/java/com/markerhub/config/CorsConfig.java
create mode 100644 vueblog-java/src/main/java/com/markerhub/config/MybatisPlusConfig.java
create mode 100644 vueblog-java/src/main/java/com/markerhub/config/ShiroConfig.java
create mode 100644 vueblog-java/src/main/java/com/markerhub/controller/AccountController.java
create mode 100644 vueblog-java/src/main/java/com/markerhub/controller/BlogController.java
create mode 100644 vueblog-java/src/main/java/com/markerhub/entity/Blog.java
create mode 100644 vueblog-java/src/main/java/com/markerhub/entity/User.java
create mode 100644 vueblog-java/src/main/java/com/markerhub/mapper/BlogMapper.java
create mode 100644 vueblog-java/src/main/java/com/markerhub/mapper/UserMapper.java
create mode 100644 vueblog-java/src/main/java/com/markerhub/service/BlogService.java
create mode 100644 vueblog-java/src/main/java/com/markerhub/service/UserService.java
create mode 100644 vueblog-java/src/main/java/com/markerhub/service/impl/BlogServiceImpl.java
create mode 100644 vueblog-java/src/main/java/com/markerhub/service/impl/UserServiceImpl.java
create mode 100644 vueblog-java/src/main/java/com/markerhub/shiro/AccountProfile.java
create mode 100644 vueblog-java/src/main/java/com/markerhub/shiro/AccountRealm.java
create mode 100644 vueblog-java/src/main/java/com/markerhub/shiro/JwtFilter.java
create mode 100644 vueblog-java/src/main/java/com/markerhub/shiro/JwtToken.java
create mode 100644 vueblog-java/src/main/java/com/markerhub/util/JwtUtils.java
create mode 100644 vueblog-java/src/main/java/com/markerhub/util/ValidationUtil.java
create mode 100644 vueblog-java/src/main/resources/META-INF/spring-devtools.properties
create mode 100644 vueblog-java/src/main/resources/application.yml
create mode 100644 vueblog-java/src/main/resources/mapper/BlogMapper.xml
create mode 100644 vueblog-java/src/main/resources/mapper/UserMapper.xml
create mode 100644 vueblog-java/src/test/java/com/markerhub/SpringbootShiroMybatisplusDemoApplicationTests.java
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..0198165
--- /dev/null
+++ b/README.md
@@ -0,0 +1 @@
+公众号:MarkerHub
\ No newline at end of file
diff --git a/vueblog-java/.gitignore b/vueblog-java/.gitignore
new file mode 100644
index 0000000..a2a3040
--- /dev/null
+++ b/vueblog-java/.gitignore
@@ -0,0 +1,31 @@
+HELP.md
+target/
+!.mvn/wrapper/maven-wrapper.jar
+!**/src/main/**
+!**/src/test/**
+
+### STS ###
+.apt_generated
+.classpath
+.factorypath
+.project
+.settings
+.springBeans
+.sts4-cache
+
+### IntelliJ IDEA ###
+.idea
+*.iws
+*.iml
+*.ipr
+
+### NetBeans ###
+/nbproject/private/
+/nbbuild/
+/dist/
+/nbdist/
+/.nb-gradle/
+build/
+
+### VS Code ###
+.vscode/
diff --git a/vueblog-java/pom.xml b/vueblog-java/pom.xml
new file mode 100644
index 0000000..16e8245
--- /dev/null
+++ b/vueblog-java/pom.xml
@@ -0,0 +1,107 @@
+
+
+ 4.0.0
+
+ org.springframework.boot
+ spring-boot-starter-parent
+ 2.2.6.RELEASE
+
+
+ com.markerhub
+ vblog-java
+ 0.0.1-SNAPSHOT
+ vblog-java
+ Demo project for Spring Boot
+
+
+ 1.8
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+
+ org.springframework.boot
+ spring-boot-devtools
+ runtime
+ true
+
+
+ org.projectlombok
+ lombok
+ true
+
+
+
+
+ com.baomidou
+ mybatis-plus-boot-starter
+ 3.2.0
+
+
+ mysql
+ mysql-connector-java
+ runtime
+
+
+
+
+ com.baomidou
+ mybatis-plus-generator
+ 3.2.0
+
+
+
+
+ org.crazycake
+ shiro-redis-spring-boot-starter
+ 3.2.1
+
+
+
+
+ cn.hutool
+ hutool-all
+ 5.3.3
+
+
+
+
+ io.jsonwebtoken
+ jjwt
+ 0.9.1
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-freemarker
+
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+ test
+
+
+ org.junit.vintage
+ junit-vintage-engine
+
+
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+
+
+
diff --git a/vueblog-java/src/main/java/com/markerhub/Application.java b/vueblog-java/src/main/java/com/markerhub/Application.java
new file mode 100644
index 0000000..eebaa9f
--- /dev/null
+++ b/vueblog-java/src/main/java/com/markerhub/Application.java
@@ -0,0 +1,14 @@
+package com.markerhub;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+public class Application {
+
+ public static void main(String[] args) {
+ SpringApplication.run(Application.class, args);
+ System.out.println("http://localhost:8080");
+ }
+
+}
diff --git a/vueblog-java/src/main/java/com/markerhub/CodeGenerator.java b/vueblog-java/src/main/java/com/markerhub/CodeGenerator.java
new file mode 100644
index 0000000..35d7a50
--- /dev/null
+++ b/vueblog-java/src/main/java/com/markerhub/CodeGenerator.java
@@ -0,0 +1,116 @@
+package com.markerhub;
+
+import com.baomidou.mybatisplus.core.exceptions.MybatisPlusException;
+import com.baomidou.mybatisplus.core.toolkit.StringPool;
+import com.baomidou.mybatisplus.core.toolkit.StringUtils;
+import com.baomidou.mybatisplus.generator.AutoGenerator;
+import com.baomidou.mybatisplus.generator.InjectionConfig;
+import com.baomidou.mybatisplus.generator.config.*;
+import com.baomidou.mybatisplus.generator.config.po.TableInfo;
+import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
+import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Scanner;
+
+// 演示例子,执行 main 方法控制台输入模块表名回车自动生成对应项目目录中
+public class CodeGenerator {
+
+ /**
+ *
+ * 读取控制台内容
+ *
+ */
+ public static String scanner(String tip) {
+ Scanner scanner = new Scanner(System.in);
+ StringBuilder help = new StringBuilder();
+ help.append("请输入" + tip + ":");
+ System.out.println(help.toString());
+ if (scanner.hasNext()) {
+ String ipt = scanner.next();
+ if (StringUtils.isNotEmpty(ipt)) {
+ return ipt;
+ }
+ }
+ throw new MybatisPlusException("请输入正确的" + tip + "!");
+ }
+
+ public static void main(String[] args) {
+ // 代码生成器
+ AutoGenerator mpg = new AutoGenerator();
+
+ // 全局配置
+ GlobalConfig gc = new GlobalConfig();
+ String projectPath = System.getProperty("user.dir");
+ gc.setOutputDir(projectPath + "/src/main/java");
+// gc.setOutputDir("D:\\test");
+ gc.setAuthor("关注公众号:MarkerHub");
+ gc.setOpen(false);
+ // gc.setSwagger2(true); 实体属性 Swagger2 注解
+ gc.setServiceName("%sService");
+ mpg.setGlobalConfig(gc);
+
+ // 数据源配置
+ DataSourceConfig dsc = new DataSourceConfig();
+ dsc.setUrl("jdbc:mysql://localhost:3306/markerhub?useUnicode=true&useSSL=false&characterEncoding=utf8&serverTimezone=UTC");
+ // dsc.setSchemaName("public");
+ dsc.setDriverName("com.mysql.cj.jdbc.Driver");
+ dsc.setUsername("root");
+ dsc.setPassword("admin");
+ mpg.setDataSource(dsc);
+
+ // 包配置
+ PackageConfig pc = new PackageConfig();
+ pc.setModuleName(null);
+ pc.setParent("com.markerhub");
+ mpg.setPackageInfo(pc);
+
+ // 自定义配置
+ InjectionConfig cfg = new InjectionConfig() {
+ @Override
+ public void initMap() {
+ // to do nothing
+ }
+ };
+
+ // 如果模板引擎是 freemarker
+ String templatePath = "/templates/mapper.xml.ftl";
+ // 如果模板引擎是 velocity
+ // String templatePath = "/templates/mapper.xml.vm";
+
+ // 自定义输出配置
+ List focList = new ArrayList<>();
+ // 自定义配置会被优先输出
+ focList.add(new FileOutConfig(templatePath) {
+ @Override
+ public String outputFile(TableInfo tableInfo) {
+ // 自定义输出文件名 , 如果你 Entity 设置了前后缀、此处注意 xml 的名称会跟着发生变化!!
+ return projectPath + "/src/main/resources/mapper/"
+ + "/" + tableInfo.getEntityName() + "Mapper" + StringPool.DOT_XML;
+ }
+ });
+
+ cfg.setFileOutConfigList(focList);
+ mpg.setCfg(cfg);
+
+ // 配置模板
+ TemplateConfig templateConfig = new TemplateConfig();
+
+ templateConfig.setXml(null);
+ mpg.setTemplate(templateConfig);
+
+ // 策略配置
+ StrategyConfig strategy = new StrategyConfig();
+ strategy.setNaming(NamingStrategy.underline_to_camel);
+ strategy.setColumnNaming(NamingStrategy.underline_to_camel);
+ strategy.setEntityLombokModel(true);
+ strategy.setRestControllerStyle(true);
+ strategy.setInclude(scanner("表名,多个英文逗号分割").split(","));
+ strategy.setControllerMappingHyphenStyle(true);
+ strategy.setTablePrefix("m_");
+ mpg.setStrategy(strategy);
+ mpg.setTemplateEngine(new FreemarkerTemplateEngine());
+ mpg.execute();
+ }
+}
\ No newline at end of file
diff --git a/vueblog-java/src/main/java/com/markerhub/common/dto/LoginDto.java b/vueblog-java/src/main/java/com/markerhub/common/dto/LoginDto.java
new file mode 100644
index 0000000..024de3b
--- /dev/null
+++ b/vueblog-java/src/main/java/com/markerhub/common/dto/LoginDto.java
@@ -0,0 +1,17 @@
+package com.markerhub.common.dto;
+
+import com.markerhub.entity.User;
+import lombok.Data;
+
+import javax.validation.constraints.NotBlank;
+import java.io.Serializable;
+
+@Data
+public class LoginDto implements Serializable {
+
+ @NotBlank(message = "昵称不能为空")
+ private String username;
+
+ @NotBlank(message = "密码不能为空")
+ private String password;
+}
diff --git a/vueblog-java/src/main/java/com/markerhub/common/exception/GlobalExcepitonHandler.java b/vueblog-java/src/main/java/com/markerhub/common/exception/GlobalExcepitonHandler.java
new file mode 100644
index 0000000..cc2d38e
--- /dev/null
+++ b/vueblog-java/src/main/java/com/markerhub/common/exception/GlobalExcepitonHandler.java
@@ -0,0 +1,61 @@
+package com.markerhub.common.exception;
+
+import com.markerhub.common.lang.Result;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.shiro.ShiroException;
+import org.springframework.http.HttpStatus;
+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 org.springframework.web.bind.annotation.RestControllerAdvice;
+
+import java.io.IOException;
+
+/**
+ * 全局异常处理
+ */
+@Slf4j
+@RestControllerAdvice
+public class GlobalExcepitonHandler {
+
+ // 捕捉shiro的异常
+ @ResponseStatus(HttpStatus.UNAUTHORIZED)
+ @ExceptionHandler(ShiroException.class)
+ public Result handle401(ShiroException e) {
+ return Result.fail(401, e.getMessage(), null);
+ }
+
+ /**
+ * 处理Assert的异常
+ */
+ @ResponseStatus(HttpStatus.BAD_REQUEST)
+ @ExceptionHandler(value = IllegalArgumentException.class)
+ public Result handler(IllegalArgumentException e) throws IOException {
+ log.error("Assert异常:-------------->{}",e.getMessage());
+ return Result.fail(e.getMessage());
+ }
+
+ /**
+ * @Validated 校验错误异常处理
+ */
+ @ResponseStatus(HttpStatus.BAD_REQUEST)
+ @ExceptionHandler(value = MethodArgumentNotValidException.class)
+ public Result handler(MethodArgumentNotValidException e) throws IOException {
+ log.error("运行时异常:-------------->",e);
+
+ BindingResult bindingResult = e.getBindingResult();
+ ObjectError objectError = bindingResult.getAllErrors().stream().findFirst().get();
+ return Result.fail(objectError.getDefaultMessage());
+ }
+
+
+ @ResponseStatus(HttpStatus.BAD_REQUEST)
+ @ExceptionHandler(value = RuntimeException.class)
+ public Result handler(RuntimeException e) throws IOException {
+ log.error("运行时异常:-------------->",e);
+ return Result.fail(e.getMessage());
+ }
+
+}
diff --git a/vueblog-java/src/main/java/com/markerhub/common/lang/Result.java b/vueblog-java/src/main/java/com/markerhub/common/lang/Result.java
new file mode 100644
index 0000000..978a311
--- /dev/null
+++ b/vueblog-java/src/main/java/com/markerhub/common/lang/Result.java
@@ -0,0 +1,42 @@
+package com.markerhub.common.lang;
+
+import lombok.Data;
+
+import java.io.Serializable;
+
+@Data
+public class Result implements Serializable {
+
+ private int code;
+ private String msg;
+ private Object data;
+
+ public static Result succ(Object data) {
+ return succ("操作成功", data);
+ }
+
+ public static Result succ(String mess, Object data) {
+ Result m = new Result();
+ m.setCode(200);
+ m.setData(data);
+ m.setMsg(mess);
+ return m;
+ }
+
+ public static Result fail(String mess) {
+ return fail(mess, null);
+ }
+
+ public static Result fail(String mess, Object data) {
+ return fail(400, mess, data);
+ }
+
+ public static Result fail(int code, String mess, Object data) {
+ Result m = new Result();
+ m.setCode(code);
+ m.setData(data);
+ m.setMsg(mess);
+ return m;
+ }
+
+}
\ No newline at end of file
diff --git a/vueblog-java/src/main/java/com/markerhub/config/CorsConfig.java b/vueblog-java/src/main/java/com/markerhub/config/CorsConfig.java
new file mode 100644
index 0000000..500b48f
--- /dev/null
+++ b/vueblog-java/src/main/java/com/markerhub/config/CorsConfig.java
@@ -0,0 +1,19 @@
+package com.markerhub.config;
+
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.servlet.config.annotation.CorsRegistry;
+import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
+
+@Configuration
+public class CorsConfig implements WebMvcConfigurer {
+
+ @Override
+ public void addCorsMappings(CorsRegistry registry) {
+ registry.addMapping("/**")
+ .allowedOrigins("*")
+ .allowedMethods("GET", "HEAD", "POST", "PUT", "DELETE", "OPTIONS")
+ .allowCredentials(true)
+ .maxAge(3600)
+ .allowedHeaders("*");
+ }
+}
\ No newline at end of file
diff --git a/vueblog-java/src/main/java/com/markerhub/config/MybatisPlusConfig.java b/vueblog-java/src/main/java/com/markerhub/config/MybatisPlusConfig.java
new file mode 100644
index 0000000..b0cd5a8
--- /dev/null
+++ b/vueblog-java/src/main/java/com/markerhub/config/MybatisPlusConfig.java
@@ -0,0 +1,19 @@
+package com.markerhub.config;
+
+import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
+import org.mybatis.spring.annotation.MapperScan;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.transaction.annotation.EnableTransactionManagement;
+
+@Configuration
+@EnableTransactionManagement
+@MapperScan("com.markerhub.mapper")
+public class MybatisPlusConfig {
+
+ @Bean
+ public PaginationInterceptor paginationInterceptor() {
+ PaginationInterceptor paginationInterceptor = new PaginationInterceptor();
+ return paginationInterceptor;
+ }
+}
\ No newline at end of file
diff --git a/vueblog-java/src/main/java/com/markerhub/config/ShiroConfig.java b/vueblog-java/src/main/java/com/markerhub/config/ShiroConfig.java
new file mode 100644
index 0000000..e6368b6
--- /dev/null
+++ b/vueblog-java/src/main/java/com/markerhub/config/ShiroConfig.java
@@ -0,0 +1,110 @@
+package com.markerhub.config;
+
+import com.markerhub.shiro.AccountRealm;
+import com.markerhub.shiro.JwtFilter;
+import io.jsonwebtoken.Jwt;
+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.LifecycleBeanPostProcessor;
+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 org.springframework.context.annotation.DependsOn;
+
+import javax.servlet.Filter;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+@Configuration
+public class ShiroConfig {
+
+ @Autowired
+ 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);
+
+ /*
+ * 关闭shiro自带的session,详情见文档
+ * http://shiro.apache.org/session-management.html#SessionManagement-StatelessApplications%28Sessionless%29
+ */
+ 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 filterMap = new LinkedHashMap<>();
+// filterMap.put("/webjars/**", "anon");
+// filterMap.put("/login", "anon");
+// filterMap.put("/swagger/**", "anon");
+// filterMap.put("/captcha.jpg", "anon");
+
+ 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 filters = new HashMap<>();
+ filters.put("jwt", jwtFilter);
+ shiroFilter.setFilters(filters);
+
+ Map 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;
+ }
+}
diff --git a/vueblog-java/src/main/java/com/markerhub/controller/AccountController.java b/vueblog-java/src/main/java/com/markerhub/controller/AccountController.java
new file mode 100644
index 0000000..fcd6dfe
--- /dev/null
+++ b/vueblog-java/src/main/java/com/markerhub/controller/AccountController.java
@@ -0,0 +1,55 @@
+package com.markerhub.controller;
+
+import cn.hutool.core.lang.Assert;
+import cn.hutool.core.map.MapUtil;
+import cn.hutool.crypto.SecureUtil;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.markerhub.common.dto.LoginDto;
+import com.markerhub.common.lang.Result;
+import com.markerhub.entity.User;
+import com.markerhub.service.UserService;
+import com.markerhub.util.JwtUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.CrossOrigin;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+@RestController
+public class AccountController {
+
+ @Autowired
+ JwtUtils jwtUtils;
+
+ @Autowired
+ UserService userService;
+
+ @CrossOrigin
+ @PostMapping("/login")
+ public Result login(@Validated @RequestBody LoginDto loginDto, HttpServletResponse response) {
+
+ User user = userService.getOne(new QueryWrapper().eq("username", loginDto.getUsername()));
+ Assert.notNull(user, "用户不存在");
+
+ if(!user.getPassword().equals(SecureUtil.md5(loginDto.getPassword()))) {
+ return Result.fail("密码错误!");
+ }
+
+ String jwt = jwtUtils.generateToken(user.getId());
+
+ response.setHeader("Authorization", jwt);
+ response.setHeader("Access-Control-Expose-Headers", "Authorization");
+
+ return Result.succ(MapUtil.builder()
+ .put("id", user.getId())
+ .put("username", user.getUsername())
+ .put("avatar", user.getAvatar())
+ .put("email", user.getEmail())
+ );
+ }
+
+}
diff --git a/vueblog-java/src/main/java/com/markerhub/controller/BlogController.java b/vueblog-java/src/main/java/com/markerhub/controller/BlogController.java
new file mode 100644
index 0000000..c563ac6
--- /dev/null
+++ b/vueblog-java/src/main/java/com/markerhub/controller/BlogController.java
@@ -0,0 +1,34 @@
+package com.markerhub.controller;
+
+import cn.hutool.core.collection.ListUtil;
+import cn.hutool.core.map.MapUtil;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.markerhub.common.lang.Result;
+import com.markerhub.service.BlogService;
+import org.apache.shiro.authz.annotation.RequiresAuthentication;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.Map;
+
+@RestController
+public class BlogController {
+
+ @Autowired
+ BlogService blogService;
+
+ @GetMapping("/blogs")
+ @RequiresAuthentication
+ public Result blogs(Integer currentPage) {
+
+ if(currentPage == null || currentPage < 1) currentPage = 1;
+
+ Page page = new Page(currentPage, 10);
+ IPage pageData = blogService.page(page);
+
+ return Result.succ(pageData);
+ }
+
+}
diff --git a/vueblog-java/src/main/java/com/markerhub/entity/Blog.java b/vueblog-java/src/main/java/com/markerhub/entity/Blog.java
new file mode 100644
index 0000000..8eb1a4e
--- /dev/null
+++ b/vueblog-java/src/main/java/com/markerhub/entity/Blog.java
@@ -0,0 +1,42 @@
+package com.markerhub.entity;
+
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import java.time.LocalDateTime;
+import java.io.Serializable;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+
+/**
+ *
+ *
+ *
+ *
+ * @author 关注公众号:MarkerHub
+ * @since 2020-05-14
+ */
+@Data
+@EqualsAndHashCode(callSuper = false)
+@Accessors(chain = true)
+@TableName("m_blog")
+public class Blog implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ @TableId(value = "id", type = IdType.AUTO)
+ private Long id;
+
+ private String title;
+
+ private String summary;
+
+ private String content;
+
+ private LocalDateTime created;
+
+ private Integer status;
+
+
+}
diff --git a/vueblog-java/src/main/java/com/markerhub/entity/User.java b/vueblog-java/src/main/java/com/markerhub/entity/User.java
new file mode 100644
index 0000000..7e9a80c
--- /dev/null
+++ b/vueblog-java/src/main/java/com/markerhub/entity/User.java
@@ -0,0 +1,49 @@
+package com.markerhub.entity;
+
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import java.time.LocalDateTime;
+import java.io.Serializable;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+
+import javax.validation.constraints.Email;
+import javax.validation.constraints.NotBlank;
+
+/**
+ *
+ * @author 关注公众号:MarkerHub
+ * @since 2020-04-20
+ */
+@Data
+@EqualsAndHashCode(callSuper = false)
+@Accessors(chain = true)
+@TableName("m_user")
+public class User implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ @TableId(value = "id", type = IdType.AUTO)
+ private Long id;
+
+ @NotBlank(message = "昵称不能为空")
+ private String username;
+
+ private String avatar;
+
+ @NotBlank(message = "邮箱不能为空")
+ @Email(message = "邮箱格式不正确")
+ private String email;
+
+ private String password;
+
+ private Integer status;
+
+ private LocalDateTime created;
+
+ private LocalDateTime lastLogin;
+
+
+}
diff --git a/vueblog-java/src/main/java/com/markerhub/mapper/BlogMapper.java b/vueblog-java/src/main/java/com/markerhub/mapper/BlogMapper.java
new file mode 100644
index 0000000..5bc571b
--- /dev/null
+++ b/vueblog-java/src/main/java/com/markerhub/mapper/BlogMapper.java
@@ -0,0 +1,16 @@
+package com.markerhub.mapper;
+
+import com.markerhub.entity.Blog;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+
+/**
+ *
+ * Mapper 接口
+ *
+ *
+ * @author 关注公众号:MarkerHub
+ * @since 2020-05-14
+ */
+public interface BlogMapper extends BaseMapper {
+
+}
diff --git a/vueblog-java/src/main/java/com/markerhub/mapper/UserMapper.java b/vueblog-java/src/main/java/com/markerhub/mapper/UserMapper.java
new file mode 100644
index 0000000..5a35aa6
--- /dev/null
+++ b/vueblog-java/src/main/java/com/markerhub/mapper/UserMapper.java
@@ -0,0 +1,16 @@
+package com.markerhub.mapper;
+
+import com.markerhub.entity.User;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+
+/**
+ *
+ * Mapper 接口
+ *
+ *
+ * @author 关注公众号:MarkerHub
+ * @since 2020-04-20
+ */
+public interface UserMapper extends BaseMapper {
+
+}
diff --git a/vueblog-java/src/main/java/com/markerhub/service/BlogService.java b/vueblog-java/src/main/java/com/markerhub/service/BlogService.java
new file mode 100644
index 0000000..0656e54
--- /dev/null
+++ b/vueblog-java/src/main/java/com/markerhub/service/BlogService.java
@@ -0,0 +1,16 @@
+package com.markerhub.service;
+
+import com.markerhub.entity.Blog;
+import com.baomidou.mybatisplus.extension.service.IService;
+
+/**
+ *
+ * 服务类
+ *
+ *
+ * @author 关注公众号:MarkerHub
+ * @since 2020-05-14
+ */
+public interface BlogService extends IService {
+
+}
diff --git a/vueblog-java/src/main/java/com/markerhub/service/UserService.java b/vueblog-java/src/main/java/com/markerhub/service/UserService.java
new file mode 100644
index 0000000..0b75508
--- /dev/null
+++ b/vueblog-java/src/main/java/com/markerhub/service/UserService.java
@@ -0,0 +1,16 @@
+package com.markerhub.service;
+
+import com.markerhub.entity.User;
+import com.baomidou.mybatisplus.extension.service.IService;
+
+/**
+ *
+ * 服务类
+ *
+ *
+ * @author 关注公众号:MarkerHub
+ * @since 2020-04-20
+ */
+public interface UserService extends IService {
+
+}
diff --git a/vueblog-java/src/main/java/com/markerhub/service/impl/BlogServiceImpl.java b/vueblog-java/src/main/java/com/markerhub/service/impl/BlogServiceImpl.java
new file mode 100644
index 0000000..56fd516
--- /dev/null
+++ b/vueblog-java/src/main/java/com/markerhub/service/impl/BlogServiceImpl.java
@@ -0,0 +1,20 @@
+package com.markerhub.service.impl;
+
+import com.markerhub.entity.Blog;
+import com.markerhub.mapper.BlogMapper;
+import com.markerhub.service.BlogService;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.springframework.stereotype.Service;
+
+/**
+ *
+ * 服务实现类
+ *
+ *
+ * @author 关注公众号:MarkerHub
+ * @since 2020-05-14
+ */
+@Service
+public class BlogServiceImpl extends ServiceImpl implements BlogService {
+
+}
diff --git a/vueblog-java/src/main/java/com/markerhub/service/impl/UserServiceImpl.java b/vueblog-java/src/main/java/com/markerhub/service/impl/UserServiceImpl.java
new file mode 100644
index 0000000..666c03f
--- /dev/null
+++ b/vueblog-java/src/main/java/com/markerhub/service/impl/UserServiceImpl.java
@@ -0,0 +1,20 @@
+package com.markerhub.service.impl;
+
+import com.markerhub.entity.User;
+import com.markerhub.mapper.UserMapper;
+import com.markerhub.service.UserService;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.springframework.stereotype.Service;
+
+/**
+ *
+ * 服务实现类
+ *
+ *
+ * @author 关注公众号:MarkerHub
+ * @since 2020-04-20
+ */
+@Service
+public class UserServiceImpl extends ServiceImpl implements UserService {
+
+}
diff --git a/vueblog-java/src/main/java/com/markerhub/shiro/AccountProfile.java b/vueblog-java/src/main/java/com/markerhub/shiro/AccountProfile.java
new file mode 100644
index 0000000..6cbde84
--- /dev/null
+++ b/vueblog-java/src/main/java/com/markerhub/shiro/AccountProfile.java
@@ -0,0 +1,13 @@
+package com.markerhub.shiro;
+
+import lombok.Data;
+
+import java.io.Serializable;
+
+@Data
+public class AccountProfile implements Serializable {
+
+ private Long id;
+ private String username;
+
+}
diff --git a/vueblog-java/src/main/java/com/markerhub/shiro/AccountRealm.java b/vueblog-java/src/main/java/com/markerhub/shiro/AccountRealm.java
new file mode 100644
index 0000000..64feacf
--- /dev/null
+++ b/vueblog-java/src/main/java/com/markerhub/shiro/AccountRealm.java
@@ -0,0 +1,58 @@
+package com.markerhub.shiro;
+
+import cn.hutool.core.bean.BeanUtil;
+import com.markerhub.entity.User;
+import com.markerhub.service.UserService;
+import com.markerhub.util.JwtUtils;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.shiro.authc.*;
+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;
+
+ @Autowired
+ UserService userService;
+
+ @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 {
+ JwtToken jwt = (JwtToken) token;
+
+ log.info("jwt----------------->{}", jwt);
+
+ String userId = jwtUtils.getClaimByToken((String) jwt.getPrincipal()).getSubject();
+
+ User user = userService.getById(Long.parseLong(userId));
+ if(user == null) {
+ throw new UnknownAccountException("账户不存在!");
+ }
+ if(user.getStatus() == -1) {
+ throw new LockedAccountException("账户已被锁定!");
+ }
+
+ AccountProfile profile = new AccountProfile();
+ BeanUtil.copyProperties(user, profile);
+
+ log.info("profile----------------->{}", profile.toString());
+
+ return new SimpleAuthenticationInfo(profile, jwt.getCredentials(), getName());
+ }
+}
diff --git a/vueblog-java/src/main/java/com/markerhub/shiro/JwtFilter.java b/vueblog-java/src/main/java/com/markerhub/shiro/JwtFilter.java
new file mode 100644
index 0000000..7915fa1
--- /dev/null
+++ b/vueblog-java/src/main/java/com/markerhub/shiro/JwtFilter.java
@@ -0,0 +1,103 @@
+package com.markerhub.shiro;
+
+import cn.hutool.http.HttpStatus;
+import cn.hutool.json.JSONUtil;
+import com.baomidou.mybatisplus.extension.api.R;
+import com.markerhub.common.lang.Result;
+import com.markerhub.util.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.util.StringUtils;
+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 {
+ // 获取 token
+ 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)) {
+// HttpServletResponse httpResponse = (HttpServletResponse) servletResponse;
+//
+// String json = JSONUtil.toJsonStr(Result.fail(HttpStatus.HTTP_UNAUTHORIZED, "invalid token", null));
+// httpResponse.getWriter().print(json);
+ 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.fail(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"));
+ // 跨域时会首先发送一个OPTIONS请求,这里我们给OPTIONS请求直接返回正常状态
+ if (httpServletRequest.getMethod().equals(RequestMethod.OPTIONS.name())) {
+ httpServletResponse.setStatus(org.springframework.http.HttpStatus.OK.value());
+ return false;
+ }
+ return super.preHandle(request, response);
+ }
+}
diff --git a/vueblog-java/src/main/java/com/markerhub/shiro/JwtToken.java b/vueblog-java/src/main/java/com/markerhub/shiro/JwtToken.java
new file mode 100644
index 0000000..6917e1e
--- /dev/null
+++ b/vueblog-java/src/main/java/com/markerhub/shiro/JwtToken.java
@@ -0,0 +1,22 @@
+package com.markerhub.shiro;
+
+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;
+ }
+}
diff --git a/vueblog-java/src/main/java/com/markerhub/util/JwtUtils.java b/vueblog-java/src/main/java/com/markerhub/util/JwtUtils.java
new file mode 100644
index 0000000..5e3ae6a
--- /dev/null
+++ b/vueblog-java/src/main/java/com/markerhub/util/JwtUtils.java
@@ -0,0 +1,62 @@
+package com.markerhub.util;
+
+import io.jsonwebtoken.Claims;
+import io.jsonwebtoken.Jwts;
+import io.jsonwebtoken.SignatureAlgorithm;
+import lombok.Data;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.stereotype.Component;
+
+import java.util.Date;
+
+/**
+ * jwt工具类
+ */
+@Slf4j
+@Data
+@Component
+@ConfigurationProperties(prefix = "markerhub.jwt")
+public class JwtUtils {
+
+ private String secret;
+ private long expire;
+ private String header;
+
+ /**
+ * 生成jwt token
+ */
+ public String generateToken(long 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){
+ log.debug("validate is token error ", e);
+ return null;
+ }
+ }
+
+ /**
+ * token是否过期
+ * @return true:过期
+ */
+ public boolean isTokenExpired(Date expiration) {
+ return expiration.before(new Date());
+ }
+}
diff --git a/vueblog-java/src/main/java/com/markerhub/util/ValidationUtil.java b/vueblog-java/src/main/java/com/markerhub/util/ValidationUtil.java
new file mode 100644
index 0000000..e942373
--- /dev/null
+++ b/vueblog-java/src/main/java/com/markerhub/util/ValidationUtil.java
@@ -0,0 +1,124 @@
+package com.markerhub.util;
+
+import lombok.Data;
+import org.hibernate.validator.HibernateValidator;
+
+import javax.validation.ConstraintViolation;
+import javax.validation.Validation;
+import javax.validation.Validator;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+
+public class ValidationUtil {
+
+ /**
+ * 开启快速结束模式 failFast (true)
+ */
+ private static Validator validator = Validation.byProvider(HibernateValidator.class).configure().failFast(false).buildValidatorFactory().getValidator();
+ /**
+ * 校验对象
+ *
+ * @param t bean
+ * @param groups 校验组
+ * @return ValidResult
+ */
+ public static ValidResult validateBean(T t,Class>...groups) {
+ ValidResult result = new ValidationUtil().new ValidResult();
+ Set> violationSet = validator.validate(t,groups);
+ boolean hasError = violationSet != null && violationSet.size() > 0;
+ result.setHasErrors(hasError);
+ if (hasError) {
+ for (ConstraintViolation violation : violationSet) {
+ result.addError(violation.getPropertyPath().toString(), violation.getMessage());
+ }
+ }
+ return result;
+ }
+ /**
+ * 校验bean的某一个属性
+ *
+ * @param obj bean
+ * @param propertyName 属性名称
+ * @return ValidResult
+ */
+ public static ValidResult validateProperty(T obj, String propertyName) {
+ ValidResult result = new ValidationUtil().new ValidResult();
+ Set> violationSet = validator.validateProperty(obj, propertyName);
+ boolean hasError = violationSet != null && violationSet.size() > 0;
+ result.setHasErrors(hasError);
+ if (hasError) {
+ for (ConstraintViolation violation : violationSet) {
+ result.addError(propertyName, violation.getMessage());
+ }
+ }
+ return result;
+ }
+ /**
+ * 校验结果类
+ */
+ @Data
+ public class ValidResult {
+
+ /**
+ * 是否有错误
+ */
+ private boolean hasErrors;
+
+ /**
+ * 错误信息
+ */
+ private List errors;
+
+ public ValidResult() {
+ this.errors = new ArrayList<>();
+ }
+ public boolean hasErrors() {
+ return hasErrors;
+ }
+
+ public void setHasErrors(boolean hasErrors) {
+ this.hasErrors = hasErrors;
+ }
+
+ /**
+ * 获取所有验证信息
+ * @return 集合形式
+ */
+ public List getAllErrors() {
+ return errors;
+ }
+ /**
+ * 获取所有验证信息
+ * @return 字符串形式
+ */
+ public String getErrors(){
+ StringBuilder sb = new StringBuilder();
+ for (ErrorMessage error : errors) {
+ sb.append(error.getPropertyPath()).append(":").append(error.getMessage()).append(" ");
+ }
+ return sb.toString();
+ }
+
+ public void addError(String propertyName, String message) {
+ this.errors.add(new ErrorMessage(propertyName, message));
+ }
+ }
+
+ @Data
+ public class ErrorMessage {
+
+ private String propertyPath;
+
+ private String message;
+
+ public ErrorMessage() {
+ }
+
+ public ErrorMessage(String propertyPath, String message) {
+ this.propertyPath = propertyPath;
+ this.message = message;
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/vueblog-java/src/main/resources/META-INF/spring-devtools.properties b/vueblog-java/src/main/resources/META-INF/spring-devtools.properties
new file mode 100644
index 0000000..1cd4a1b
--- /dev/null
+++ b/vueblog-java/src/main/resources/META-INF/spring-devtools.properties
@@ -0,0 +1 @@
+restart.include.shiro-redis=/shiro-[\\w-\\.]+jar
\ No newline at end of file
diff --git a/vueblog-java/src/main/resources/application.yml b/vueblog-java/src/main/resources/application.yml
new file mode 100644
index 0000000..4c94479
--- /dev/null
+++ b/vueblog-java/src/main/resources/application.yml
@@ -0,0 +1,22 @@
+server:
+ port: 8081
+# DataSource Config
+spring:
+ datasource:
+ driver-class-name: com.mysql.cj.jdbc.Driver
+ url: jdbc:mysql://localhost:3306/markerhub?useUnicode=true&useSSL=false&characterEncoding=utf8&serverTimezone=UTC
+ username: root
+ password: admin
+mybatis-plus:
+ mapper-locations: classpath*:/mapper/**Mapper.xml
+shiro-redis:
+ enabled: true
+ redis-manager:
+ host: 127.0.0.1:6379
+markerhub:
+ jwt:
+ # 加密秘钥
+ secret: f4e2e52034348f86b67cde581c0f9eb5
+ # token有效时长,7天,单位秒
+ expire: 604800
+ header: token
diff --git a/vueblog-java/src/main/resources/mapper/BlogMapper.xml b/vueblog-java/src/main/resources/mapper/BlogMapper.xml
new file mode 100644
index 0000000..4b610b7
--- /dev/null
+++ b/vueblog-java/src/main/resources/mapper/BlogMapper.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/vueblog-java/src/main/resources/mapper/UserMapper.xml b/vueblog-java/src/main/resources/mapper/UserMapper.xml
new file mode 100644
index 0000000..8df9f9b
--- /dev/null
+++ b/vueblog-java/src/main/resources/mapper/UserMapper.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/vueblog-java/src/test/java/com/markerhub/SpringbootShiroMybatisplusDemoApplicationTests.java b/vueblog-java/src/test/java/com/markerhub/SpringbootShiroMybatisplusDemoApplicationTests.java
new file mode 100644
index 0000000..34a74a4
--- /dev/null
+++ b/vueblog-java/src/test/java/com/markerhub/SpringbootShiroMybatisplusDemoApplicationTests.java
@@ -0,0 +1,13 @@
+package com.markerhub;
+
+import org.junit.jupiter.api.Test;
+import org.springframework.boot.test.context.SpringBootTest;
+
+@SpringBootTest
+class SpringbootShiroMybatisplusDemoApplicationTests {
+
+ @Test
+ void contextLoads() {
+ }
+
+}