小项目练习 介绍 SSM + Vue 前后端分离的一个知识点整合,简单的对登录业务进行梳理
项目环境 Windows 10/Jdk 11/Tomcat 9.0/Maven 3.6/Mysql 8.0/Redis 7.0
所用技术 Spring/Spring Mvc/Mybatis/Vue/Element Plus/Axios
主要模块 登录的处理以及信息的CRUD
项目意义 个人所学知识点整合
介绍一下项目搭建过程 前端搭建
vue的一个脚手架 一键搭建前端项目框架
1 2 3 4 5 6 7 8 9 10 { "dependencies" : { "axios" : "^0.27.2" , "core-js" : "^3.8.3" , "element-plus" : "^2.2.12" , "vue" : "^3.2.13" , "vue-router" : "4" , "vuex" : "^4.0.2" }, }
vue的路由 实现路由跳转
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 import store from '@/store' ;import storage from '@/util/storage' ;import { createRouter, createWebHistory } from 'vue-router' const routes = [ { path : '/' , component : () => import ('@/components/login/LoginShow.vue' ), }, { name : 'login' , path : '/login' , component : () => import ('@/components/login/LoginShow.vue' ), }, { name : 'main' , path : '/main' , component : () => import ('@/components/main/IndexShow.vue' ), children : [ { name : 'user' , path : '/user' , component : () => import ('@/components/system/user/userShow.vue' ), } ] } ] const router = createRouter({ history : createWebHistory(), routes, }) router.beforeEach((to ) => { if (to.name === 'login' ) { return true } if (!store.getters.isLogin) { if (!storage.getSessionObject("loginUser" )) { router.push({ name : 'login' }) } else { store.dispatch("RECOVERY_USER" ); store.dispatch("GET_INFO" ); } } return true }) export default router
vuex存储前端数据
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 import { login, logout,getInfo } from '@/api/user' ;import storage from '@/util/storage.js' ;const user = { state : { username : "" , nickname : "" , token : "" , roles : [], permissions : [] }, getters : { isLogin (state ) { return state.username !== '' && state.token !== '' ; }, permissions (state ) { return state.permissions; }, roles (state ) { return state.roles; }, }, mutations : { SAVE_USERNAME (state, username ) { state.username = username }, SAVE_NICKNAME (state, nickname ) { state.nickname = nickname; }, SAVE_TOKEN (state, token ) { state.token = token; }, SAVE_ROLES (state, roles ) { state.roles = roles; }, SAVE_PERMISSIONS (state, permissions ) { state.permissions = permissions; } }, actions : { LOGIN ({ commit }, user ) { return new Promise (function (resolve ) { login(user).then(res => { commit("SAVE_USERNAME" , res.data.ydlUser.userName); commit("SAVE_NICKNAME" , res.data.ydlUser.nickName); commit("SAVE_TOKEN" , res.data.token); storage.saveSessionObject("loginUser" , res.data); resolve(res); }) }) }, LOGOUT ({ commit } ) { return new Promise (function (resolve ) { logout(user).then(res => { commit("SAVE_USERNAME" , '' ); commit("SAVE_NICKNAME" , '' ); commit("SAVE_TOKEN" , '' ); storage.remove("loginUser" ); resolve(res); }) }) }, RECOVERY_USER ({ commit } ) { let loginUser = storage.getSessionObject("loginUser" ); if (loginUser){ commit("SAVE_USERNAME" , loginUser.ydlUser.userName); commit("SAVE_NICKNAME" , loginUser.ydlUser.nickName); commit("SAVE_TOKEN" , loginUser.token); } }, GET_INFO ({ commit } ) { return new Promise (resolve => { getInfo().then(res => { commit("SAVE_ROLES" , res.data.roles); commit("SAVE_PERMISSIONS" , res.data.perms); resolve(); }) }) }, } } export default user
axios发送请求
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 import request from "@/api" ;export function login (data ) { return request({ url : '/login' , method : 'post' , data : data }) } export function logout ( ) { return request({ url : '/logout' , method : 'get' , }) } export function listUser (data ) { return request({ url : '/ydlUser' , method : 'get' , params : data }) } export function getInfo ( ) { return request({ url : '/ydlUser/getInfo' , method : 'get' , }) } export function getById (id ) { return request({ url : '/ydlUser/' + id, method : 'get' , }) } export function deleteUser (id ) { return request({ url : '/ydlUser/' + id, method : 'delete' , }) } export function add (data ) { return request({ url : '/ydlUser' , method : 'post' , data : data }) } export function update (data ) { return request({ url : '/ydlUser' , method : 'put' , data : data }) }
项目结构
后端搭建
搭建后端框架结构
项目所需依赖
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 <?xml version="1.0" encoding="UTF-8"?> <project xmlns ="http://maven.apache.org/POM/4.0.0" xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation ="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" > <modelVersion > 4.0.0</modelVersion > <groupId > com.dream.xiaobo</groupId > <artifactId > ssm-pro</artifactId > <packaging > pom</packaging > <version > 1.0-SNAPSHOT</version > <modules > <module > system-admin</module > </modules > <name > ruoyi</name > <properties > <maven.compiler.source > 11</maven.compiler.source > <maven.compiler.target > 11</maven.compiler.target > <project.build.sourceEncoding > utf-8</project.build.sourceEncoding > <javax.servlet.version > 4.0.1</javax.servlet.version > <spring.version > 5.2.18.RELEASE</spring.version > <spring-data-commons.version > 2.6.0</spring-data-commons.version > <aspectjweaver.version > 1.9.6</aspectjweaver.version > <lombok.version > 1.18.22</lombok.version > <jackson.version > 2.13.1</jackson.version > <validation-api.version > 2.0.1.Final</validation-api.version > <hibernate-validator > 6.0.9.Final</hibernate-validator > <logback-classic.version > 1.2.6</logback-classic.version > <commons-fileupload.version > 1.3.3</commons-fileupload.version > <druid.version > 1.2.8</druid.version > <mysql-connector-java.version > 8.0.26</mysql-connector-java.version > <mybatis.version > 3.5.5</mybatis.version > <mybatis-spring.version > 2.0.6</mybatis-spring.version > <redis.version > 4.0.1</redis.version > <commons-lang3.version > 3.1</commons-lang3.version > </properties > <dependencyManagement > <dependencies > <dependency > <groupId > javax.servlet</groupId > <artifactId > javax.servlet-api</artifactId > <version > ${javax.servlet.version}</version > </dependency > <dependency > <groupId > org.springframework</groupId > <artifactId > spring-webmvc</artifactId > <version > ${spring.version}</version > </dependency > <dependency > <groupId > org.springframework</groupId > <artifactId > spring-jdbc</artifactId > <version > ${spring.version}</version > </dependency > <dependency > <groupId > org.springframework.data</groupId > <artifactId > spring-data-commons</artifactId > <version > ${spring-data-commons.version}</version > </dependency > <dependency > <groupId > org.aspectj</groupId > <artifactId > aspectjweaver</artifactId > <version > ${aspectjweaver.version}</version > </dependency > <dependency > <groupId > org.projectlombok</groupId > <artifactId > lombok</artifactId > <version > ${lombok.version}</version > </dependency > <dependency > <groupId > com.fasterxml.jackson.core</groupId > <artifactId > jackson-core</artifactId > <version > ${jackson.version}</version > </dependency > <dependency > <groupId > com.fasterxml.jackson.core</groupId > <artifactId > jackson-annotations</artifactId > <version > ${jackson.version}</version > </dependency > <dependency > <groupId > com.fasterxml.jackson.core</groupId > <artifactId > jackson-databind</artifactId > <version > ${jackson.version}</version > </dependency > <dependency > <groupId > javax.validation</groupId > <artifactId > validation-api</artifactId > <version > ${validation-api.version}</version > </dependency > <dependency > <groupId > org.hibernate</groupId > <artifactId > hibernate-validator</artifactId > <version > ${hibernate-validator}</version > </dependency > <dependency > <groupId > ch.qos.logback</groupId > <artifactId > logback-classic</artifactId > <version > ${logback-classic.version}</version > </dependency > <dependency > <groupId > commons-fileupload</groupId > <artifactId > commons-fileupload</artifactId > <version > ${commons-fileupload.version}</version > </dependency > <dependency > <groupId > com.alibaba</groupId > <artifactId > druid</artifactId > <version > ${druid.version}</version > </dependency > <dependency > <groupId > mysql</groupId > <artifactId > mysql-connector-java</artifactId > <version > ${mysql-connector-java.version}</version > </dependency > <dependency > <groupId > org.mybatis</groupId > <artifactId > mybatis</artifactId > <version > ${mybatis.version}</version > </dependency > <dependency > <groupId > org.mybatis</groupId > <artifactId > mybatis-spring</artifactId > <version > ${mybatis-spring.version}</version > </dependency > <dependency > <groupId > redis.clients</groupId > <artifactId > jedis</artifactId > <version > ${redis.version}</version > </dependency > <dependency > <groupId > eu.bitwalker</groupId > <artifactId > UserAgentUtils</artifactId > <version > 1.21</version > </dependency > <dependency > <groupId > org.apache.commons</groupId > <artifactId > commons-lang3</artifactId > <version > ${commons-lang3.version}</version > </dependency > </dependencies > </dependencyManagement > <build > <plugins > <plugin > <groupId > org.apache.maven.plugins</groupId > <artifactId > maven-compiler-plugin</artifactId > <version > 3.1</version > <configuration > <source > ${java.version}</source > <target > ${java.version}</target > <encoding > ${project.build.sourceEncoding}</encoding > </configuration > </plugin > </plugins > </build > </project >
web项目所需的设置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 <?xml version="1.0" encoding="UTF-8"?> <web-app xmlns ="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation ="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" version ="4.0" > <listener > <listener-class > org.springframework.web.context.ContextLoaderListener</listener-class > </listener > <context-param > <param-name > contextConfigLocation</param-name > <param-value > classpath:application.xml</param-value > </context-param > <servlet > <servlet-name > springmvc</servlet-name > <servlet-class > org.springframework.web.servlet.DispatcherServlet</servlet-class > <init-param > <param-name > contextConfigLocation</param-name > <param-value > classpath:application.xml</param-value > </init-param > <load-on-startup > 1</load-on-startup > </servlet > <servlet-mapping > <servlet-name > springmvc</servlet-name > <url-pattern > /</url-pattern > </servlet-mapping > <filter > <filter-name > encodingFilter</filter-name > <filter-class > org.springframework.web.filter.CharacterEncodingFilter</filter-class > <init-param > <param-name > encoding</param-name > <param-value > UTF-8</param-value > </init-param > </filter > <filter-mapping > <filter-name > encodingFilter</filter-name > <url-pattern > /*</url-pattern > </filter-mapping > <filter > <filter-name > xssFilter</filter-name > <filter-class > com.dream.xiaobo.filter.XssFilter</filter-class > </filter > <filter-mapping > <filter-name > xssFilter</filter-name > <url-pattern > /*</url-pattern > </filter-mapping > </web-app >
配置jdbc.properties数据库连接信息文件
连接数据库所需的设置
1 2 3 4 user =root password =xiaobo url =jdbc:mysql://localhost:3306/db_ssm-pro?characterEncoding=utf8&useUnicode=true&useSSL=false&serverTimezone=GMT%2B8 driverName =com.mysql.cj.jdbc.Driver
配置spring/spring mvc/mybatis所需的设置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 <?xml version="1.0" encoding="UTF-8"?> <beans xmlns ="http://www.springframework.org/schema/beans" xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance" xmlns:context ="http://www.springframework.org/schema/context" xmlns:mvc ="http://www.springframework.org/schema/mvc" xmlns:tx ="http://www.springframework.org/schema/tx" xmlns:aop ="http://www.springframework.org/schema/aop" xmlns:mybatis ="http://mybatis.org/schema/mybatis-spring" xmlns:task ="http://www.springframework.org/schema/task" xsi:schemaLocation ="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/tx https://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task.xsd http://mybatis.org/schema/mybatis-spring https://mybatis.org/schema/mybatis-spring.xsd http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd" > <context:component-scan base-package ="com.dream.xiaobo" /> <aop:aspectj-autoproxy /> <bean id ="multipartResolver" class ="org.springframework.web.multipart.commons.CommonsMultipartResolver" > <property name ="defaultEncoding" value ="utf-8" /> <property name ="maxUploadSize" value ="10485760" /> <property name ="maxInMemorySize" value ="40960" /> </bean > <bean class ="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping" /> <bean class ="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter" /> <bean class ="org.springframework.web.servlet.view.InternalResourceViewResolver" id ="internalResourceViewResolver" > <property name ="prefix" value ="/WEB-INF/page/" /> <property name ="suffix" value =".jsp" /> <property name ="order" value ="10" /> </bean > <bean id ="customObjectMapper" class ="com.dream.xiaobo.configuration.CustomObjectMapper" /> <mvc:annotation-driven > <mvc:message-converters > <bean class ="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter" > <property name ="objectMapper" ref ="customObjectMapper" /> <property name ="supportedMediaTypes" > <list > <value > text/plain;charset=UTF-8</value > <value > application/json;charset=UTF-8</value > </list > </property > </bean > </mvc:message-converters > </mvc:annotation-driven > <mvc:interceptors > <mvc:interceptor > <mvc:mapping path ="/**" /> <mvc:exclude-mapping path ="/login" /> <bean id ="loginInterceptor" class ="com.dream.xiaobo.interceptor.LoginInterceptor" /> </mvc:interceptor > <mvc:interceptor > <mvc:mapping path ="/**" /> <bean id ="repeatSubmitInterceptor" class ="com.dream.xiaobo.interceptor.RepeatSubmitInterceptor" /> </mvc:interceptor > </mvc:interceptors > <context:property-placeholder location ="classpath:jdbc.properties" /> <mybatis:scan base-package ="com.dream.xiaobo.dao" /> <bean id ="dataSource" class ="com.alibaba.druid.pool.DruidDataSource" > <property name ="url" value ="${url}" /> <property name ="driverClassName" value ="${driverName}" /> <property name ="username" value ="${user}" /> <property name ="password" value ="${password}" /> </bean > <bean id ="sqlSessionFactory" class ="org.mybatis.spring.SqlSessionFactoryBean" > <property name ="dataSource" ref ="dataSource" /> <property name ="mapperLocations" value ="classpath:mapper/**/*.xml" /> <property name ="configuration" > <bean class ="org.apache.ibatis.session.Configuration" > <property name ="mapUnderscoreToCamelCase" value ="true" /> <property name ="logImpl" value ="org.apache.ibatis.logging.stdout.StdOutImpl" /> <property name ="logPrefix" value ="ssm-pro_" /> </bean > </property > </bean > <bean id ="transactionManager" class ="org.springframework.jdbc.datasource.DataSourceTransactionManager" > <property name ="dataSource" ref ="dataSource" /> </bean > <tx:advice id ="txAdvice" transaction-manager ="transactionManager" > <tx:attributes > <tx:method name ="get*" read-only ="true" propagation ="SUPPORTS" /> <tx:method name ="select*" read-only ="true" propagation ="SUPPORTS" /> <tx:method name ="update*" read-only ="false" propagation ="REQUIRED" /> <tx:method name ="delete*" read-only ="false" propagation ="REQUIRED" /> <tx:method name ="insert*" read-only ="false" propagation ="REQUIRED" /> </tx:attributes > </tx:advice > <bean id ="jedisPool" class ="redis.clients.jedis.JedisPool" > <constructor-arg name ="host" value ="0.0.0.0" /> <constructor-arg name ="port" value ="6379" /> <property name ="minIdle" value ="20" /> <property name ="maxIdle" value ="30" /> <property name ="maxTotal" value ="200" /> </bean > <task:annotation-driven executor ="ydl-logger" /> <task:executor id ="ydl-logger" pool-size ="10-20" keep-alive ="120" rejection-policy ="ABORT" queue-capacity ="500" /> </beans >
配置日志框架所需的设置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 <?xml version="1.0" encoding="UTF-8"?> <configuration > <property name ="log.path" value ="D://logs" /> <property name ="log.pattern" value ="%d{HH:mm:ss.SSS} [%thread] %-5level %logger{20} - [%method,%line] - %msg%n" /> <appender name ="console" class ="ch.qos.logback.core.ConsoleAppender" > <encoder > <pattern > ${log.pattern}</pattern > </encoder > </appender > <appender name ="file_info" class ="ch.qos.logback.core.rolling.RollingFileAppender" > <file > ${log.path}/sys-info.log</file > <rollingPolicy class ="ch.qos.logback.core.rolling.TimeBasedRollingPolicy" > <fileNamePattern > ${log.path}/sys-info.%d{yyyy-MM-dd}.log</fileNamePattern > <maxHistory > 60</maxHistory > </rollingPolicy > <encoder > <pattern > ${log.pattern}</pattern > </encoder > <filter class ="ch.qos.logback.classic.filter.LevelFilter" > <level > INFO</level > <onMatch > ACCEPT</onMatch > <onMismatch > DENY</onMismatch > </filter > </appender > <appender name ="file_error" class ="ch.qos.logback.core.rolling.RollingFileAppender" > <file > ${log.path}/sys-error.log</file > <rollingPolicy class ="ch.qos.logback.core.rolling.TimeBasedRollingPolicy" > <fileNamePattern > ${log.path}/sys-error.%d{yyyy-MM-dd}.log</fileNamePattern > <maxHistory > 60</maxHistory > </rollingPolicy > <encoder > <pattern > ${log.pattern}</pattern > </encoder > <filter class ="ch.qos.logback.classic.filter.LevelFilter" > <level > ERROR</level > <onMatch > ACCEPT</onMatch > <onMismatch > DENY</onMismatch > </filter > </appender > <logger name ="com.dream.xiaobo" level ="info" /> <logger name ="org.springframework" level ="warn" /> <root level ="info" > <appender-ref ref ="console" /> <appender-ref ref ="file_info" /> <appender-ref ref ="file_error" /> </root > </configuration >
创建CustomObjectMapper类来配置jackson的序列化和反序列化
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 public class CustomObjectMapper extends ObjectMapper { public CustomObjectMapper () { super (); configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false ); setTimeZone(TimeZone.getTimeZone("GMT+8" )); setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss" )); configure(SerializationFeature.WRITE_NULL_MAP_VALUES, false ); setSerializationInclusion(JsonInclude.Include.NON_NULL); getDeserializationConfig().withoutFeatures(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES); configure(SerializationFeature.WRITE_ENUMS_USING_TO_STRING, true ); } }
项目结构
数据库设计 简单的设计了六个表、并不复杂、主要学习登录的逻辑以及整合的过程
table_role(角色表)
table_user_role(用户角色关联表)
table_menu(菜单表)
table_role_menu(角色菜单关联表)
table_log(日志表)
介绍一下项目处理问题的过程 跨域问题 有两种解决方案,一种在后端解决,一种在前端解决
后端解决方案 这种方案是前端发送请求直接到达后端服务器,所以这个时候需要在后端进行处理,我们后端需要使用一个注解来进行处理@CrossOrigin
配置文件进行全局处理
1 2 3 <mvc:cors > <mvc:mapping path ="/*" allowed-methods ="*" allowed-origins ="*" /> </mvc:cors >
前端解决方案 这种方案是前端发送请求到前端服务器,前端服务器作为一个代理,然后在通过前端服务器发送请求到后端服务器,因为服务器之间不存在跨域问题
修改vue.config.js
1 2 3 4 5 6 module .exports = { devServer : { port : 80 , proxy : "http://localhost:8088" } }
配置axios.js
1 2 3 4 5 6 7 8 9 const request = axios.create({ baseURL : 'http://localhost:80/' , timeout : 10000 , headers : {'Content-Type' : 'application/json;charset=utf-8' } })
登录的过程(只介绍主要逻辑) 前端处理
写出登录页面,data()进行数据双向绑定以及数据简单校验
method: 处理一些事件点击方法,方法进行相应的逻辑处理
doLogin() 前端的登录逻辑,校验user中的validate是否存在,如果存在在store中取出结果集,在对其结果集中status状态码进行校验,如果为200,则证明访问成功,成功的时候需要进行对应的权限认证相关获取,然后进行对应的路由跳转,否则访问失败
这里介绍一下store
这个就相当于Java中的定义变量
这个相当于Java中的set方法
这个相当于Java中的get方法
对外提供方法,并进行逻辑处理
全局的路由守卫 会在每次路由跳转的时候执行 to:你要去哪个路由 from:你从哪个路由来
我们在这进行校验,如果去的是登陆页面,就放行,在此进行校验,校验用户名和token是否为空,如果不为空则继续进行校验,校验是否拿存储对象,进行相应的处理
后端处理 登录处理 后端首先进行controller处理,用@Validated,BindingResult进行校验处理,然后进行登录业务逻辑的续写
登录的service首先根据用户名进行查询拿到对象,将其对象进行校验,进行相应的自定义异常处理,在对其密码的正确性进行校验,也进行自定义异常的处理,生成Token,根据UUID进行生成,在进行request和User-Agent的获取,根据request拿到IP,通过IP拿到该用户的各个信息,在通过拿到的信息进行JSON序列化,拿到IP地址的省市区,通过创建者模式创建登录的用户信息,根据用户名生成一个key前缀token:username:查询token:userName:下的所有的key,然后再清除之前的Key保证最新的Token,并且唯一并且存储到Redis中,并返回对象
登出处理 获取到Request和头部信息中的AUTHORIZATION,根据token: * :获取到的token进行查询,如果查询到了在清空Redis中的数据
登录拦截器 根据AUTHORIZATION拿到信息校验是否存在,如果存在,在Redis中查看是否存在Token信息,如果存在给Redis中的Token信息续命,重新设置Token过期时间,然后放行,反之全部进行拦截
RBAC管理 RBAC RBAC(Role-Based Access Control:基于角色的访问控制)就是,用户有哪些角色,该角色有哪些权限
RBAC组成
每个用户都有唯一的UID识别,并被授予不同的角色
不同角色具有不同的权限
访问权限
RBAC通过定义角色的权限,并对用户授予某个角色从而来控制用户的权限,实现了用户和权限的逻辑分离
鉴权 关键SQL
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 SELECT u.user_id user_id, username, nick_name, r.role_id, r.role_name, r.role_tag, m.menu_id, m.menu_name, m.perms FROM table_user u LEFT JOIN `table_user_role` ur ON u.user_id = ur.user_id LEFT JOIN table_role r ON ur.role_id = r.role_id LEFT JOIN table_role_menu rm ON r.role_id = rm.role_id LEFT JOIN table_menu m ON rm.menu_id = m.menu_id where u.del_flag = 0 and r.del_flag = 0 and u.user_id = #{userId}
后端鉴权
拿到登录的用户信息,根据id进行查询用户对应的权限,进行截取,拿到prems: [system:user:add,system:user:update]格式的信息,roleTags:[admin,hr,user]格式信息,然后以perm:token:prems,roles:token:prems格式以此存入到Redis中进行保存,然后自定义两个注解即可,然后通过AOP即可使用注解完成切入
日志输出 自定义一个日志注解,然后可以自定义哪个接口需要进行监听即可对其进行日志的输出,然后通过AOP进行处理,拿到相关的信息依次存入到数据库即可,但有一个要注意的点是日志不是主要的业务逻辑,所以大量的日志输出不太优化,会影响主业务,所以我们在此要进行异步处理,要开启spring的异步处理,需要在application.xml进行相应的配置,然后就是用到线程来处理,开启一个线程池,让主业务是一个线程,为日志开启另一个线程,来解决这个问题
表单重复提交 主要的表单是不允许重复提交的,所以要进行处理,这里自定义一个注解,然后设置一个拦截器拦截
xss攻击 就是在表单里直接输入标签来进行脚本攻击,vue的本身做了防御机制,很多框架都做了这个防御机制
解决xss攻击的核心方法就是处理掉那些可能产生问题的标签,或者通过转义,或者将半角的尖括号转化为全角,在或者直接干掉一些特殊标签
声明
此项目只有登录业务和用户信息的CRUD
源码自取,公众号回复ssm_vue_project_test
自己学习整理,如有侵权,通知即删
正确的开始 微小的长进 然后持续 嘿 我是小博 带你一起看我目之所及的世界……