Vue+SSM+Element-Ui

前后端分离练习

SSM: Spring 、SpringMVC、 MyBatis

整体规划:先搭建前端,接下来后端,最后整合。

一、创建vue项目

1、安装nodejs

傻瓜式安装即可 官网: http://nodejs.cn/download/

检查安装是否成功

IMG_256

有问题可看 https://www.runoob.com/nodejs/nodejs-npm.html

安装淘宝镜像

(由于npm在国外速度慢,直接用我们的)

cmd里直接运行 npm install -g cnpm --registry=https://registry.npm.taobao.org

3、使用cnpm安装vue

cmd里直接运行 cnpm install vue

4、全局安装vue脚手架工具

cmd里直接运行 cnpm install --global vue-cli

5、创建vue项目

cmd里直接运行 vue init webpack 项目

至此,vue项目创建完成。在你创建项目位置根目录运行:npm run dev

注意:如果在初始化创建项目时有错误,运行时 先 在你创建的 项目位置根目录 cnpm
install,再 npm run dev

浏览器访问

运行成功!!! 接下来就可以写页面啦(这里我们用Element UI)

Element UI教程:https://element.eleme.cn/#/zh-CN/component/installation

6、编写简单页面

1、cmd进入你的项目,安装Element Ui cnpm install element-ui -S

安装完成后,在router/index.js或者main.js里引入

import ElementUI from ‘element-ui’;

import ‘element-ui/lib/theme-chalk/index.css’;

Vue.use(ElementUI);

这时候就可以开心的使用Element Ui组件库了

2、这里先模拟一个登陆功能(1.有表单校验,2、默认用户名wzz,密码521125,登陆成功跳到列表页,失败友情提示)
列表页旁边是代码结构图

效果如图

项目目录

3、代码介绍:

3.1、router/index.js (侧栏路由编码)

import Vue from ‘vue’ import Router from ‘vue-router’ import ElementUI from ‘element-ui’; import ‘element-ui/lib/theme-chalk/index.css’; Vue.use(ElementUI); Vue.use(Router) //json格式数据 let menu=[ { path:‘/user’, name:‘layoutYHGL’, component:()=>import(‘@/views/layout/Layout’), meta:{ title:‘用户管理’, icon:‘el-icon-user’, menu:true, funcNode:‘1’ }, children:[ { path:‘/user/userList’, name:‘UserList’, component:()=>import(‘@/views/user/UserList’), meta:{ title:‘用户列表’, icon:‘el-icon-notebook-2’, menu:true, funcNode:‘1-1’ } }, { path:‘/user/addUser’, name:‘UserAdd’, component:()=>import(‘@/views/user/UserAdd’), meta:{ title:‘用户添加’, icon:‘el-icon-circle-plus-outline’, menu:true, funcNode:‘1-2’ } } ] }, { path:‘/role’, redirect:‘user/userList’, meta:{ title:‘角色管理’, icon:‘el-icon-help’, menu:true } }, { path:‘/sys’, name:‘layoutXTGL’, component:()=>import(‘@/views/layout/Layout’), meta:{ title:‘系统管理’, icon:‘el-icon-setting’, menu:true, funcNode:‘2’ }, children:[ { path:‘/sys/sysLogList’, name:‘SysLogList’, component:()=>import(‘@/views/sys/SysLogList’), meta:{ title:‘系统访问日志’, icon:‘el-icon-notebook-1’, menu:true, funcNode:‘2-1’ } } ] }, { path:‘’, redirect:‘login’, meta:{ menu:false } }, { path:‘/login’, name:‘Login’, component:()=>import(‘@/views/login/Login’), meta:{ menu:false } } ] export default new Router({ routes:menu, })

3.2、layout/Layout.vue (对侧栏信息的布局,使用了v-for,v-on ,v-if)

<template> <el-container style=“height: 100%;”> <!-- 头部 --> <el-header style=“text-align: right; font-size: 12px;background-color: whitesmoke;”> <el-dropdown> <i class=“el-icon-setting” style=“margin-right: 15px”></i> <el-dropdown-menu slot=“dropdown”> <el-dropdown-item>查看</el-dropdown-item> <el-dropdown-item>新增</el-dropdown-item> <el-dropdown-item>删除</el-dropdown-item> </el-dropdown-menu> </el-dropdown> <span>王小虎</span> </el-header> <el-container> <!-- 左侧栏 --> <el-aside width=“200px”> <el-menu> <!–如果菜单(menu)是true 循环侧栏路由列表 --> <template v-for=“item in menuData” v-if=“item.meta.menu”> <!-- 这里必须设置index,相当唯一标识这个菜单标签,否则菜单列表点击后随意展开 --> <el-submenu :index=“item.meta.funcNode”> <template slot=“title”><i :class=“item.meta.icon”></i></template> <!-- 如果菜单有孩子菜单,则循环孩子菜单 --> <template v-for=“itemC in item.children” v-if=“item.children”> <el-menu-item :index=“itemC.meta.funcNode” @click=“clickMenu(itemC)”><i :class=“itemC.meta.icon”></i></el-menu-item> </template> </el-submenu> </template> </el-menu> </el-aside> <!-- 内容渲染 --> <el-main style=“background-color: white;”> <router-view/> </el-main> </el-container> </el-container> </template> <script> export default { data() { return { /* 获取挂载的routes ($router相当于一个全局的路由器对象,里面含有很多属性和子对象 ) (options是一个对象,有成员:1、data函数成员 2、methods对象成员 3、模板template 4、挂载元素el 5、生命周期钩子 6、props属性声明 7、computed计算成员 8、watch监视成员) */ menuData: this.$router.options.routes } }, methods: { clickMenu(item){ this.$router.push({path:item.path}) //跳转的路由对象 //this.$router.push({name:item.name}) 通过name跳转 } } } </script> <style> .el-header { background-color: #B3C0D1; color: #333; line-height: 60px; } .el-aside, .el-menu, .el-submenu, .el-menu-item { background-color: rgb(238, 241, 246); } body { margin: 0px; } </style>

3.3、App.vue

<template> <div id=“app”> <router-view/> </div> </template> <script> export default { name: ‘App’ } </script> <style> #app{} </style>

3.4、index.html
(主要是对html,body样式设置height:100%,为解决子模块设置height:100%无效)

<!DOCTYPE html> <html> <head> <meta charset=“utf-8”> <meta name=“viewport” content=“width=device-width,initial-scale=1.0”> <title>myproject</title> </head> <body> <div id=“app”></div> <!-- built files will be auto injected --> </body> <style> html,body,#app{ height: 100%; } </style> </html>

3.5、login/Login.vue

<template> <div class=“box”> <div id=“login” style=“width: 320px;height: 300px;text-align: center;”> <el-form :model=“loginForm” ref=“loginForm” :rules=“rules”> <el-form-item> <span style=“color: white;font-family: 楷体;font-size: 26px;”>用&nbsp;户 登 录 </span> </el-form-item> <el-form-item prop=“userName”> <el-input type=“text” v-model=“loginForm.userName” placeholder=“用户名”> <template slot=“prepend”><i class=“el-icon-user” style=“font-size: 20px; color: white;”></i></template> </el-input> </el-form-item> <el-form-item prop=“password”> <el-input type=“text” v-model=“loginForm.password” placeholder=“密码” show-password> <template slot=“prepend”><i class=“el-icon-lock” style=“font-size: 20px;color: white;”></i></template> </el-input> </el-form-item> <el-form-item> <el-button type=“primary” size=“medium” :loading=“loading” style=“font-size: 20px;font-family: 微软雅黑;width: 320px;” @click=“clickLogin”>登&nbsp;  录</el-button> </el-form-item> </el-form> </div> </div> </template> <script> export default { data() { var validateUserName = (rule, value, callback) => { if (value.length === 0) { return callback(new Error(‘请输入用户名’)) } else { callback() } } var validatePassword = (rule, value, callback) => { if (value.length === 0) { callback(new Error(‘请输入密码’)) } else if (value.length < 3) { callback(new Error(‘密码不能小于3位’)) } else { callback() } } return { loginForm: { userName: ‘’, password: ‘’ }, loading: false, //登陆加载效果 rules: { userName: [{ required: true, trigger: ‘blur’, validator: validateUserName }], password: [{ required: true, trigger: ‘blur’, validator: validatePassword }] } } }, methods: { clickLogin() { this.$refs.loginForm.validate(valid => { if (valid) { this.loading = true setTimeout(() => { if (this.loginForm.userName === ‘wzz’ && this.loginForm.password === ‘521125’) { this.$router.push({ name: ‘layoutYHGL’ }); } else { this.$notify({ title: ‘登录提示’, message: ‘用户名或密码错误’, position: ‘bottom-right’, type: ‘error’ }); this.loading=false; } }, 3000); } else { return false; } }) } } } </script> <style scoped=“scoped”> .box { display: flex; height: 100%; justify-content: center; align-items: center; } </style> <style> .el-input-group__prepend { padding: 0px 15px; background-color: #CCCCCC; border: 1 solid #72767B; } body { background-color: #72767B; margin: 0px; } </style>

3.6、sys/SysLogList.vue,user/UserAdd.vue,user/UserList.vue
(这几个就是加了一个各自的<h3></h3>标签) 如下

<template> <div><h3>用户添加</h3></div> </template> <script> </script> <style> </style>

至此,前端暂时结束。

二、创建SSM项目

前言:后台使用ssm搭建,对以前学习知识的一个回顾,与此同时来发现自己不足。这里主要采用配置文件方式进行,有部分注解。

**目标:**搭建ssm框架,并测试成功;(其中也有aop切面的编写)

一、开发工具

IDEA2018.2.4_X64,MYSQL5.7,TOMCAT8.0.22,MAVEN3.5.3,JDK1.8.0_144

二、ssm框架搭建

项目结构图

1、配置文件

1.1 pom.xml

<?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.wzz</groupId> <artifactId>SSM</artifactId> <version>1.0-SNAPSHOT</version> <packaging>war</packaging> <name>SSM Maven Webapp</name> <!-- FIXME change it to the project’s website --> <url>http://www.example.com</url> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.target>1.8</maven.compiler.target> <spring.version>5.0.2.RELEASE</spring.version> <slf4j.version>1.6.6</slf4j.version> <log4j.version>1.2.12</log4j.version> <shiro.version>1.2.3</shiro.version> <mysql.version>8.0.11</mysql.version> <mybatis.version>3.4.5</mybatis.version> </properties> <dependencies> <!–Spring提供的对AspectJ框架的整合–> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.6.8</version> </dependency> <!–Spring的面向切面编程,提供AOP(面向切面编程)的实现–> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aop</artifactId> <version>${spring.version}</version> </dependency> <!–Spring IOC的基础实现,包含访问配置文件、创建和管理bean等–> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-beans</artifactId> <version>${spring.version}</version> </dependency> <!–在基础IOC功能上提供扩展服务,此外还提供许多企业级服务的支持, 有邮件服务、任务调度、JNDI定位,EJB集成、远程访问、缓存以及多种视图层框架的支持–> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>${spring.version}</version> </dependency> <!–Spring context的扩展支持,用于MVC方面–> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context-support</artifactId> <version>${spring.version}</version> </dependency> <!–Spring的核心工具包–> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>${spring.version}</version> </dependency> <!–spring的jdbc包–> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>${spring.version}</version> </dependency> <!–为JDBC、Hibernate、JDO、JPA等提供的一致的声明式和编程式事务管理–> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-tx</artifactId> <version>${spring.version}</version> </dependency> <!–包含Web应用开发时,用到Spring框架时所需的核心类, 包括自动载入WebApplicationContext特性的类、Struts与JSF集成类、文件上传的支持类、Filter类和大量工具辅助类–> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> <version>${spring.version}</version> </dependency> <!–包含SpringMVC框架相关的所有类。 包含国际化、标签、Theme、视图展现的FreeMarker、JasperReports、Tiles、Velocity、XSLT相关类。 当然,如果你的应用使用了独立的MVC框架,则无需这个JAR文件里的任何类–> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>${spring.version}</version> </dependency> <!–对JUNIT等测试框架的简单封装–> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>${spring.version}</version> </dependency> <!–servlet–> <dependency> <groupId>javax.servlet</groupId> <artifactId>servlet-api</artifactId> <version>2.5</version> <scope>provided</scope> </dependency> <!–mysql驱动包–> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>${mysql.version}</version> </dependency> <!–mybatis–> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>${mybatis.version}</version> </dependency> <!–mybatis与spring整合需要的包 --> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis-spring</artifactId> <version>1.3.0</version> </dependency> <!–mybatis分页插件–> <dependency> <groupId>com.github.pagehelper</groupId> <artifactId>pagehelper</artifactId> <version>5.1.10</version> </dependency> <!–c3p0–> <dependency> <groupId>c3p0</groupId> <artifactId>c3p0</artifactId> <version>0.9.1.2</version> <type>jar</type> <scope>compile</scope> </dependency> <!–spring推荐的json转化包–> <!–jackson–> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.9.0</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-core</artifactId> <version>2.9.0</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-annotations</artifactId> <version>2.9.0</version> </dependency> <!–阿里巴巴的json转化包–> <!–fastjson–> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.1.37</version> </dependency> <!–浏览器工具类–> <dependency> <groupId>eu.bitwalker</groupId> <artifactId>UserAgentUtils</artifactId> <version>1.20</version> </dependency> <!-- 日志相关包 --> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>${log4j.version}</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>${slf4j.version}</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> <version>${slf4j.version}</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.11</version> <scope>compile</scope> </dependency> </dependencies> <build> <finalName>SSM</finalName> <!–编译时,使得java包下的.properties和.xml文件包含在类路径下,方便配置扫描mapper的xml文件–> <resources> <resource> <directory>src/main/java</directory> <includes> <include>**/*.properties</include> <include>**/*.xml</include> </includes> <filtering>false</filtering> </resource> </resources> <pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) --> <plugins> <plugin> <artifactId>maven-clean-plugin</artifactId> <version>3.1.0</version> </plugin> <!-- see http://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_war_packaging --> <plugin> <artifactId>maven-resources-plugin</artifactId> <version>3.0.2</version> </plugin> <plugin> <artifactId>maven-compiler-plugin</artifactId> <version>3.8.0</version> </plugin> <plugin> <artifactId>maven-surefire-plugin</artifactId> <version>2.22.1</version> </plugin> <plugin> <artifactId>maven-war-plugin</artifactId> <version>3.2.2</version> </plugin> <plugin> <artifactId>maven-install-plugin</artifactId> <version>2.5.2</version> </plugin> <plugin> <artifactId>maven-deploy-plugin</artifactId> <version>2.8.2</version> </plugin> </plugins> </pluginManagement> </build> </project>

1.2 applicationContext.xml

<?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:aop=“http://www.springframework.org/schema/aop” xmlns:tx=“http://www.springframework.org/schema/tx” xmlns:context=“http://www.springframework.org/schema/context” xsi:schemaLocation=“http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd”> <!–开启注解扫描,因为spring和springMVC是父子容器,但是它们有各自独立性,这里排除Controller层,如果不排除,都全部扫描,就可能会出现Controller的方法无法拦截、Bean被多次加载等问题;–> <context:component-scan base-package=“com.wzz”> <context:exclude-filter type=“annotation” expression=“org.springframework.stereotype.Controller”/> <context:exclude-filter type=“annotation” expression=“org.springframework.web.bind.annotation.RestController”/> </context:component-scan> <!–spring整合mybatis–> <context:property-placeholder location=“classpath:db.properties”/> <!–配置连接池–> <bean id=“dataSource” class=“com.mchange.v2.c3p0.ComboPooledDataSource”> <property name=“driverClass” value=“${jdbc.driver}”/> <property name=“jdbcUrl” value=“${jdbc.url}”/> <property name=“user” value=“${jdbc.userName}”/> <property name=“password” value=“${jdbc.password}”/> <property name=“initialPoolSize” value=“${jdbc.c3p0.initialPoolSize}”/> <property name=“maxPoolSize” value=“${jdbc.c3p0.maxPoolSize}”/> <property name=“minPoolSize” value=“${jdbc.c3p0.minPoolSize}”/> <property name=“maxIdleTime” value=“${jdbc.c3p0.maxIdleTime}”/> </bean> <!–配置SqlSessionFactory对象–> <bean id=“sqlSessionFactory” class=“org.mybatis.spring.SqlSessionFactoryBean”> <property name=“dataSource” ref=“dataSource”/> <property name=“configLocation” value=“classpath:sqlMapConfig.xml”/> <property name=“mapperLocations” value=“classpath:com/wzz/mapper/*.xml”/> <!–配置mybatis分页插件–> <property name=“plugins”> <array> <bean class=“com.github.pagehelper.PageInterceptor”> <property name=“properties”> <props> <prop key=“helperDialect”>mysql</prop> <prop key=“reasonable”>true</prop> </props> </property> </bean> </array> </property> </bean> <!–配置接口所在的包–> <bean id=“mapperScanner” class=“org.mybatis.spring.mapper.MapperScannerConfigurer”> <property name=“basePackage” value=“com.wzz.mapper”/> </bean> <!–配置spring框架声明式事务管理–> <!–配置事务管理器–> <bean id=“transactionManager” class=“org.springframework.jdbc.datasource.DataSourceTransactionManager”> <property name=“dataSource” ref=“dataSource”/> </bean> <!–配置事务通知–> <tx:advice id=“txAdvice” transaction-manager=“transactionManager”> <!–事务的属性–> <tx:attributes> <!–SUPPORTS代表支持当前事务,如果当前没有事务,就以非事务方式执行。–> <tx:method name=“query*” propagation=“SUPPORTS” read-only=“true”/> <!–DEFAULT代表以数据库的隔离级别–> <tx:method name=“*” isolation=“DEFAULT”/> </tx:attributes> </tx:advice> <!–配置Aop增强–> <aop:config> <!–配置切入点表达式–> <!–* *…*.*(…) 修饰符(可省略) 返回类型 包.包…包.类.方法.(参数)–> <aop:pointcut id=“pt” expression=“execution(* com.wzz.service.impl.*.*(…))”/> <!–建立事务与切入点之间的关系–> <aop:advisor advice-ref=“txAdvice” pointcut-ref=“pt”/> </aop:config> </beans>

1.3 springMVC.xml

<?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:aop=“http://www.springframework.org/schema/aop” xmlns:context=“http://www.springframework.org/schema/context” xmlns:mvc=“http://www.springframework.org/schema/mvc” xsi:schemaLocation=“http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd”> <!–springMVC值扫描controller–> <context:component-scan base-package=“com.wzz.controller”/> <!–配置日志切面–> <aop:config> <aop:pointcut id=“pt” expression=“execution(* com.wzz.controller.*.*(…))”/> <!–日志切面–> <aop:aspect id=“” ref=“sysAccessLogAspect”> <!–前置通知–> <aop:before method=“doBefore” pointcut-ref=“pt”></aop:before> <!–后置通知–> <aop:after-returning method=“doAfter” pointcut-ref=“pt”></aop:after-returning> </aop:aspect> </aop:config> <!–视图解析器 这里不需要视图解析器,因为不处理jsp,或者html,咱们是前后端分离,后端只负责返回数据即可–> <!–<bean id=“internalResourceViewResolver” class=“org.springframework.web.servlet.view.InternalResourceViewResolver”>–> <!–<property name=“prefix” value=“/WEB-INF/pages/”/>–> <!–<property name=“suffix” value=“.jsp”/>–> <!–</bean>–> <!–&lt;!–过滤静态资源–>–> <!–<mvc:resources mapping=“/css/**” location=“/css/”/>–> <!–<mvc:resources mapping=“/images/**” location=“/images/”/>–> <!–<mvc:resources mapping=“/js/**” location=“/js/”/>–> <!–springMVC框架流程 1、 用户发起请求到前端控制器(DispatcherServlet),前端控制器没有能力处理业务逻辑; 2、 通过HandlerMapping查找模型(Controller、Handler); 3、 返回执行链,执行链包含了2部分内容,Handler对象以及拦截器(组); 4、 通过HandlerAdapter执行模型(Handler) 5、 适配器调用Handler对象处理业务逻辑; 6、 模型处理完业务逻辑,返回ModelAndView对象,view不是真正的视图对象,而是视图名称; 7、 将ModelAndView对象返回给前端控制器; 8、 前端控制器通过视图名称经过视图解析器查找视图对象; 9、 返回视图对象; 10、前端控制器渲染视图; 11、返回给前端控制器; 12、前端控制器将视图(html、json、xml、Excel)返回给用户;–> <!–开启springMVC注解支持–> <mvc:annotation-driven/> </beans>

springMVC.xml为什么要配置注解驱动?https://blog.csdn.net/weixin_42529699/article/details/88085405

1.4 sqlMapConfig.xml

<?xml version=“1.0” encoding=“UTF-8” ?> <!DOCTYPE configuration PUBLIC “-//mybatis.org//DTD Config 3.0//EN” “http://mybatis.org/dtd/mybatis-3-config.dtd”> <configuration> <!–别名配置 对model包下的所有起一个别名,默认是它的类名(不分大小写)–> <typeAliases> <package name=“com.wzz.model”/> </typeAliases> </configuration>

1.5 log4j.properties

log4j.rootLogger=DEBUG,Console,File log4j.appender.Console=org.apache.log4j.ConsoleAppender log4j.appender.Console.Target=System.out log4j.appender.Console.layout = org.apache.log4j.PatternLayout log4j.appender.Console.layout.ConversionPattern=[%c] - %m%n log4j.appender.File =org.apache.log4j.RollingFileAppender log4j.appender.File.File = logs/SSM.log log4j.appender.File.MaxFileSize = 10MB log4j.appender.File.Threshold = ALL log4j.appender.File.layout =org.apache.log4j.PatternLayout log4j.appender.File.layout.ConversionPattern =[%p] [%d{yyyy-MM-ddHH\\\:mm\\\:ss}][%c]%m%n log4j.logger.java.sql.ResultSet=DEBUG log4j.logger.java.sql.Connection=DEBUG log4j.logger.java.sql.PreparedStatement=DEBUG

1.6 db.properties

jdbc.driver=com.mysql.cj.jdbc.Driver jdbc.url=jdbc:mysql://localhost:3306/ssm?serverTimezone=GMT%2B8&useSSL=false jdbc.userName=wzz jdbc.password=521125 #--------------------------------------------------------- # c3p0反空闲设置,防止8小时失效问题28800 #--------------------------------------------------------- #idleConnectionTestPeriod要小于MySQL的wait_timeout #If true, an operation will be performed at every connection checkout to verify that the connection is valid. jdbc.c3p0.testConnectionOnCheckout=false #If true, an operation will be performed asynchronously at every connection checkin to verify that the connection is valid. jdbc.c3p0.testConnectionOnCheckin=true #If this is a number greater than 0, c3p0 will test all idle, pooled but unchecked-out connections, every this number of seconds. jdbc.c3p0.idleConnectionTestPeriod=3600 #--------------------------------------------------------- # c3p0连接池配置 #--------------------------------------------------------- #initialPoolSize, minPoolSize, maxPoolSize define the number of Connections that will be pooled. #Please ensure that minPoolSize <= maxPoolSize. #Unreasonable values of initialPoolSize will be ignored, and minPoolSize will be used instead. jdbc.c3p0.initialPoolSize=10 jdbc.c3p0.minPoolSize=10 jdbc.c3p0.maxPoolSize=50 #maxIdleTime defines how many seconds a Connection should be permitted to go unused before being culled from the pool. jdbc.c3p0.maxIdleTime=3600

1.7 web.xml

<!DOCTYPE web-app PUBLIC “-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN” “http://java.sun.com/dtd/web-app_2_3.dtd” > <web-app> <display-name>Archetype Created Web Application</display-name> <!–配置spring的监听器,默认加载WEB-INF目录下的applicationContext.xml配置文件–> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <!–设置配置文件的路径–> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:applicationContext.xml</param-value> </context-param> <!–配置前段控制器–> <servlet> <servlet-name>dispatcherServlet</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <!–加载springMVC.xml配置文件–> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:springMVC.xml</param-value> </init-param> <!–contextLoaderListener监听器初始化完毕后,开始初始化web.xml中配置的Servlet,servlet可以配置多个,加载顺序按照load-on-startup的值,值越小,servlet的优先级越高,就越先被加载–> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>dispatcherServlet</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> <!–解决中文乱码过滤器–> <filter> <filter-name>characterEncodingFilter</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>characterEncodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> </web-app>

源码文件

按结构图,从上往下出场

2.1 SysAccessLogAspect.java

package com.wzz.aspect; import org.aspectj.lang.JoinPoint; import org.springframework.stereotype.Component; /** * @ClassName SysAccessLogAspect * @Description TODO 系统访问日志切面类 * @Author zhengsongbo * Version 1.0 **/ @Component public class SysAccessLogAspect { public void doBefore(JoinPoint jp){ System.out.println(“前置通知执行啦”); } public void doAfter(JoinPoint jp){ System.out.println(“后置通知执行啦”); } }

2.2 UserController.java

package com.wzz.controller; import com.wzz.service.IUserService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; import java.util.Map; /** * @ClassName UserController * @Description TODO 用户控制层 * @Author zhengsongbo * Version 1.0 **/ @Controller public class UserController { @Autowired private IUserService userService; @RequestMapping(“/test”) @ResponseBody public Map queryUserList(){ System.out.println(“controller层执行啦”); Map<String, Object> resultMap = userService.queryUserList(); return resultMap; } }

2.3 UserMapper.java

package com.wzz.mapper; import com.wzz.model.User; import java.util.List; /** * @ClassName UserMapper * @Description TODO 用户持久层接口 * @Author zhengsongbo * Version 1.0 **/ public interface UserMapper { List<User> queryUserList(); }

2.4 UserMapper.xml

<?xml version=“1.0” encoding=“UTF-8” ?> <!DOCTYPE mapper PUBLIC “-//mybatis.org//DTD Mapper 3.0//EN” “http://mybatis.org/dtd/mybatis-3-mapper.dtd”> <mapper namespace=“com.wzz.mapper.UserMapper”> <!–因为在sqlMapConfig.xml中配置了别名,所以直接写user就可以–> <select id=“queryUserList” resultType=“user”> select * from tbUser </select> </mapper>

2.5 User.java

package com.wzz.model; import java.io.Serializable; /** * @ClassName User * @Description TODO 用户类 * @Author zhengsongbo * Version 1.0 **/ public class User implements Serializable { private Integer id; //用户标识 private String uid; //uid private String userName; //用户名 private String password; //密码 private String uName; //姓名 private Integer age; //年龄 private Integer sex; //性别 //setter and getter and toString }

2.6 UserServiceImpl.java

package com.wzz.service.impl; import com.wzz.mapper.UserMapper; import com.wzz.model.User; import com.wzz.service.IUserService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.HashMap; import java.util.List; import java.util.Map; /** * @ClassName UserServiceImpl * @Description TODO 用户业务层实现类 * @Author zhengsongbo * Version 1.0 **/ @Service public class UserServiceImpl implements IUserService { @Autowired private UserMapper userMapper; @Override public Map<String,Object> queryUserList() { System.out.println(“service执行啦”); List<User> userList = userMapper.queryUserList(); System.out.println(“调用了mapper层”); Map<String,Object> resultMap=new HashMap<>(); resultMap.put(“userList”,userList); return resultMap; } }

2.7 IUserService.java

package com.wzz.service; import java.util.Map; /** * @ClassName IUserService * @Description TODO 用户业务层接口 * @Author zhengsongbo * Version 1.0 **/ public interface IUserService { Map<String,Object> queryUserList(); }

SQL脚本

sql脚本仅结构,没有数据,自行添加

/* Navicat Premium Data Transfer Source Server : ssm Source Server Type : MySQL Source Server Version : 80011 Source Host : localhost:3306 Source Schema : ssm Target Server Type : MySQL Target Server Version : 80011 File Encoding : 65001 Date: 02/08/2019 08:24:19 */ SET NAMES utf8mb4; SET FOREIGN_KEY_CHECKS = 0; – ---------------------------- – Table structure for tbuser – ---------------------------- DROP TABLE IF EXISTS `tbuser`; CREATE TABLE `tbuser` ( `id` int(11) NOT NULL AUTO_INCREMENT, `uId` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, `userName` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, `password` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, `uName` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, `age` int(11) NULL DEFAULT NULL, `sex` int(11) NULL DEFAULT NULL, PRIMARY KEY (`id`) USING BTREE ) ENGINE = InnoDB AUTO_INCREMENT = 19 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic; SET FOREIGN_KEY_CHECKS = 1;

三、测试

1、Tomcat配置

若没有此工具栏,直接点击视图(View),勾选工具栏(Toolbar)即可

点击配置,添加本地Tomcat

点击Deployment,选择+ Artifact 选择war,或者 war exploded(热部署配置选择的,)

应用,确定即可

至此,就可以进行测试了(成功返回了数据)

控制台情况,测试没问题

至此,完成了ssm搭建

实现功能

**规划:**实现登录,用户列表查询,访问日志aop;

开始先解决跨域:在目录config/index.js配置

3.1 config/index.js

‘use strict’ // Template version: 1.3.1 // see http://vuejs-templates.github.io/webpack for documentation. const path = require(‘path’) module.exports = { dev: { // Paths assetsSubDirectory: ‘static’, assetsPublicPath: ‘/’, /* ‘/api’ 为匹配项,target 为被请求的后台地址 changeOrigin设置为true,那么本地会虚拟一个服务端接收你的请求并代你发送该请求,这样就不会有跨域问题了,只适用于开发环境.如果上线的话,可以考虑nginx pathRewrite 是用来重写地址,将前缀 ‘/api’ 转为 ‘/’,如果本身的接口地址就有 ‘/api’ 这种通用前缀,就可以把 pathRewrite 删掉,或者你可以自定义一个公共接口匹配地址 如:请求http://127.0.0.1:8080/user/queryUserList,就可以写成:/api/user/queryUserList */ proxyTable: { ‘/api’:{ target:‘http://127.0.0.1:8080’, changeOrigin:true, pathRewrite:{ ‘^/api’:‘/’ } } }, // Various Dev Server settings host: ‘localhost’, // can be overwritten by process.env.HOST port: 8081, // can be overwritten by process.env.PORT, if port is in use, a free one will be determined autoOpenBrowser: false, errorOverlay: true, notifyOnErrors: true, poll: false, // https://webpack.js.org/configuration/dev-server/#devserver-watchoptions- /** * Source Maps */ // https://webpack.js.org/configuration/devtool/#development devtool: ‘cheap-module-eval-source-map’, // If you have problems debugging vue-files in devtools, // set this to false - it *may* help // https://vue-loader.vuejs.org/en/options.html#cachebusting cacheBusting: true, cssSourceMap: true }, build: { // Template for index.html index: path.resolve(__dirname, ‘…/dist/index.html’), // Paths assetsRoot: path.resolve(__dirname, ‘…/dist’), assetsSubDirectory: ‘static’, assetsPublicPath: ‘/’, /** * Source Maps */ productionSourceMap: true, // https://webpack.js.org/configuration/devtool/#production devtool: ‘#source-map’, // Gzip off by default as many popular static hosts such as // Surge or Netlify already gzip all static assets for you. // Before setting to `true`, make sure to: // npm install --save-dev compression-webpack-plugin productionGzip: false, productionGzipExtensions: [‘js’, ‘css’], // Run the build command with an extra argument to // View the bundle analyzer report after build finishes: // `npm run build --report` // Set to `true` or `false` to always turn it on or off bundleAnalyzerReport: process.env.npm_config_report } }

3.2 tbSysLog.sql

/* Navicat Premium Data Transfer Source Server : ssm Source Server Type : MySQL Source Server Version : 80011 Source Host : localhost:3306 Source Schema : ssm Target Server Type : MySQL Target Server Version : 80011 File Encoding : 65001 Date: 05/08/2019 16:44:14 */ SET NAMES utf8mb4; SET FOREIGN_KEY_CHECKS = 0; – ---------------------------- – Table structure for tbsyslog – ---------------------------- DROP TABLE IF EXISTS `tbsyslog`; CREATE TABLE `tbsyslog` ( `id` int(11) NOT NULL AUTO_INCREMENT, `logId` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, `accessDate` datetime(0) NULL DEFAULT NULL, `requestType` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, `accessInterface` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, `interfaceParams` text CHARACTER SET utf8 COLLATE utf8_general_ci NULL, `accessSource` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, `accessIp` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, `executeTime` int(11) NULL DEFAULT NULL, PRIMARY KEY (`id`) USING BTREE ) ENGINE = InnoDB AUTO_INCREMENT = 761 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic; SET FOREIGN_KEY_CHECKS = 1;

前端项目结构图 后端项目结构图

3.4 前端

3.4.1安装axios

cnpm install axios -S

3.4.2 config/dev.env.js

添加 BASE_URL:‘“/api”’ (因为这里在3里要引用,也可不配置,你在3里写死就行)

3.4.3 封装axios

utils/request.js

import axios from ‘axios’ //引入axios /* 创建axios实例 */ const service = axios.create({ //这个process.env.BASE_URL在config/dev.evn.js、prod.evn.js里面进行配置 baseURL: process.env.BASE_URL, // api的base_url timeout: 5000 // 请求超时时间 }); /*response拦截器,进行错误处理*/ service.interceptors.response.use(response => { return response; }, error => { // 失败处理 switch (error.response.status) { case 400: error.message = ‘错误请求’ break; case 401: error.message = ‘未授权,请重新登录’ break; case 403: error.message = ‘拒绝访问’ break; case 404: error.message = ‘请求错误,未找到该资源’ break; case 405: error.message = ‘请求方法未允许’ break; case 408: error.message = ‘请求超时’ break; case 500: error.message = ‘服务器端出错’ break; case 501: error.message = ‘网络未实现’ break; case 502: error.message = ‘网络错误’ break; case 503: error.message = ‘服务不可用’ break; case 504: error.message = ‘网络超时’ break; case 505: error.message = ‘http版本不支持该请求’ break; default: error.message = `连接错误${error.response.status}` } return Promise.reject(error); } ); /*reuqest拦截器*/ service.interceptors.request.use(config => { return config; }, error => { return Promise.reject(error); } ); export default service;

3.4.4封装一个公共的axios请求API

api/commonAPI.js

import request from ‘@/utils/request’ export function commonAPI(api,postData){ if(postData===‘’){ return request({ url:‘/’+api, method:‘post’ }) }else{ return request({ url:‘/’+api, method:‘post’, data:postData }) } }

3.4.5封装一个日期格式转化的api

utils/index.js

/** * 格式为yyyy-MM-dd OR yyyy-MM-dd HH:mm:ss * @param {Object} date 日期对象 * @param {Object} hasTime 是否有时间 true有时间,false没有时间 */ export function formatDate(date,hasTime){ var hasTime = hasTime;//可传第二个参数false,返回yyyy-MM-dd var d = date; var year = d.getFullYear(); var month = (d.getMonth()+1)<10 ? ‘0’+(d.getMonth()+1) : (d.getMonth()+1); var day = d.getDate()<10 ? ‘0’+d.getDate() : d.getDate(); var hour = d.getHours()<10 ? ‘0’+d.getHours() : d.getHours(); var minute = d.getMinutes()<10 ? ‘0’+d.getMinutes() : d.getMinutes(); var second = d.getSeconds()<10 ? ‘0’+d.getSeconds() : d.getSeconds(); if(hasTime){ return [year, month, day].join(‘-’) + " " + [hour, minute, second].join(‘:’); }else{ return [year, month, day].join(‘-’); } }

3.4.6 vue文件

1.login/Login.vue

<template> <div class=“box”> <div id=“login” style=“width: 320px;height: 300px;text-align: center;”> <el-form :model=“loginForm” ref=“loginForm” :rules=“rules”> <el-form-item> <span style=“color: white;font-family: 楷体;font-size: 26px;”>用&nbsp;户 登 录 </span> </el-form-item> <el-form-item prop=“userName”> <el-input type=“text” v-model=“loginForm.userName” placeholder=“用户名”> <template slot=“prepend”><i class=“el-icon-user” style=“font-size: 20px; color: white;”></i></template> </el-input> </el-form-item> <el-form-item prop=“password”> <el-input type=“text” v-model=“loginForm.password” placeholder=“密码” show-password> <template slot=“prepend”><i class=“el-icon-lock” style=“font-size: 20px;color: white;”></i></template> </el-input> </el-form-item> <el-form-item> <el-button type=“primary” size=“medium” :loading=“loading” style=“font-size: 20px;font-family: 微软雅黑;width: 320px;” @click=“clickLogin”>登&nbsp;  录</el-button> </el-form-item> </el-form> </div> </div> </template> <script> import { commonAPI } from ‘@/api/commonAPI’; export default { data() { var validateUserName = (rule, value, callback) => { if (value.length === 0) { return callback(new Error(‘请输入用户名’)) } else { callback() } } var validatePassword = (rule, value, callback) => { if (value.length === 0) { callback(new Error(‘请输入密码’)) } else if (value.length < 3) { callback(new Error(‘密码不能小于3位’)) } else { callback() } } return { loginForm: { userName: ‘’, password: ‘’ }, loading: false, //登陆加载效果 rules: { userName: [{ required: true, trigger: ‘blur’, validator: validateUserName }], password: [{ required: true, trigger: ‘blur’, validator: validatePassword }] } } }, methods: { clickLogin() { this.$refs.loginForm.validate(valid => { if (valid) {//校验成功 this.loading = true setTimeout(() => {//为了看到登录转圈圈的加载效果,这里来一个延迟2秒发送请求 //封装的公共请求API commonAPI(‘queryUser’, this.loginForm).then(res => { let data = res.data; if (data.info.code === ‘0’ && data.data === ‘OK’) { this.$router.push({ name: ‘layoutYHGL’ }); } else { this.$notify({ title: ‘登录提示’, message: ‘用户名或密码错误’, position: ‘bottom-right’, type: ‘error’ }); this.loading = false; } }).catch(error=>{ this.loading = false; this.$notify({//这里采用element ui的一个错误显示效果模板 title: ‘登录提示’, message: error.message, position: ‘bottom-right’, type: ‘error’ }); }) }, 2000); } else { return false; } }) } } } </script> <style scoped=“scoped”> .box { display: flex; height: 100%; justify-content: center; align-items: center; } </style> <style> .el-input-group__prepend { padding: 0px 15px; background-color: #CCCCCC; border: 1 solid #72767B; } body { background-color: #72767B; margin: 0px; } </style>

2.sys/SysLogList.vue

<template> <el-container> <el-header style=“background-color:white”> <el-form :inline=“true” :model=“formInline” class=“demo-form-inline” size=“mini”> <el-form-item label=“访问时间”> <el-date-picker class=“dateStyle” v-model=“formInline.beginTime” value-format=“yyyy-MM-dd HH:mm:ss” @change=“dataFormat” type=“datetime” placeholder=“选择日期时间”></el-date-picker> 至&nbsp;<el-date-picker class=“dateStyle” v-model=“formInline.endTime” value-format=“yyyy-MM-dd HH:mm:ss” @change=“dataFormat” type=“datetime” placeholder=“选择日期时间”></el-date-picker> </el-form-item> <el-form-item> <el-button type=“primary” class=“btn” @click=“onSubmit”><i class=“el-icon-search”></i>查询</el-button> </el-form-item> <el-form-item> <el-button type=“danger” class=“btn” @click=“resetting”><i class=“el-icon-refresh”></i>重置</el-button> </el-form-item> </el-form> </el-header> <el-main class=“elMain”> <el-table v-loading=“loading” :data=“tableData” height=“100%” stripe border size=“mini”> <el-table-column align=“center” label=“访问时间” prop=“accessDate” width=“140”></el-table-column> <el-table-column align=“center” label=“请求方式” prop=“requestType” width=“90”></el-table-column> <el-table-column align=“center” label=“请求接口” prop=“accessInterface” width=“280”></el-table-column> <el-table-column header-align=“center” align=“left” label=“接口参数” width=“90”> <template slot-scope=“scope” v-if=“scope.row.interfaceParams”> <el-popover v-if=“scope.row.interfaceParams.length>10” placement=“left-end” width=“200” trigger=“hover” :content=“scope.row.interfaceParams”> <span slot=“reference” style=“text-overflow: ellipsis;white-space:nowrap;overflow: hidden;”></span> </el-popover> <span v-else></span> </template> </el-table-column> <el-table-column align=“center” label=“访问来源” prop=“accessSource” width=“263”></el-table-column> <el-table-column align=“center” label=“访问IP” prop=“accessIp” width=“130”></el-table-column> <el-table-column align=“center” label=“执行时长” prop=“executeTime” width=“90”></el-table-column> </el-table> </el-main> <el-footer> <div style=“padding: 15px 0;text-align: right;”> <el-pagination background @size-change=“handleSizeChange” @current-change=“handleCurrentChange” :current-page=“formInline.pageNum” :page-sizes=“pageSizes” :page-size=“formInline.pageSize” layout=“total, sizes, prev, pager, next, jumper” :total=“pageTotal”> </el-pagination> </div> </el-footer> </el-container> </template> <script> import {formatDate} from ‘@/utils/index’; import {commonAPI} from ‘@/api/commonAPI’; export default { data() { return { tableData: [], loading: false, formInline: { pageNum: 1, pageSize: 10, beginTime: new Date(new Date().getTime()-3600*1000*24*7), endTime: new Date() }, pageSizes: [5, 10, 15, 20], pageTotal: 0 } }, created() { this.formInline.beginTime=formatDate(this.formInline.beginTime,true); this.formInline.endTime=formatDate(this.formInline.endTime,true); this.getData(); }, methods: { getData() { this.loading = true, commonAPI(‘sysLogList’,this.formInline) .then(res => { this.loading = false; this.tableData = res.data.data.rows; this.pageTotal = res.data.data.total; }) }, dataFormat(val){ console.log(val); }, onSubmit() {//查询 this.getData(); }, resetting() {//重置 this.formInline.beginTime=formatDate(new Date(new Date().getTime()-3600*1000*24*7),true); this.formInline.endTime=formatDate(new Date(),true); this.getData(); }, handleSizeChange(val) { //console.log(`每页 ${val} 条`); this.formInline.pageSize = val; this.formInline.pageNum = 1; this.getData(); }, handleCurrentChange(val) { //console.log(`当前页: ${val}`); this.formInline.pageNum = val; this.getData(); } } } </script> <style scoped> .dateStyle,.btn { margin-top: 18px; } .elMain { height: 418px; } </style> <style> .el-main { padding: 5px 10px; } .el-table th { height: 45px; font-size: 16px; font-family: 微软雅黑; font-weight: 500; color: darkblue; } body { margin: 0px; } </style>

3.user/UserList.vue

<template> <el-container> <el-header style=“background-color:white”> <el-form :inline=“true” :model=“formInline” class=“demo-form-inline” size=“mini”> <el-form-item label=“用户名”> <el-input v-model=“formInline.userName” placeholder=“用户名” class=“elInput”></el-input> </el-form-item> <el-form-item label=“性别”> <el-select v-model=“formInline.sex” class=“elInput”> <el-option label=“全部” value=“”></el-option> <el-option label=“男” value=“0”></el-option> <el-option label=“女” value=“1”></el-option> </el-select> </el-form-item> <el-form-item> <el-button type=“primary” class=“btn” @click=“onSubmit”><i class=“el-icon-search”></i>查询</el-button> </el-form-item> <el-form-item> <el-button type=“danger” class=“btn” @click=“resetting”><i class=“el-icon-refresh”></i>重置</el-button> </el-form-item> </el-form> </el-header> <el-main class=“elMain”> <el-table v-loading=“loading” :data=“tableData” height=“100%” stripe border size=“mini”> <el-table-column align=“center” label=“编号” prop=“uid”></el-table-column> <el-table-column align=“center” label=“用户名” prop=“userName”></el-table-column> <el-table-column align=“center” label=“姓名” prop=“uName”></el-table-column> <el-table-column align=“center” label=“年龄” prop=“age”></el-table-column> <el-table-column align=“center” label=“性别”> <template slot-scope=“scope”> <span v-if=“scope.row.sex===0”>男</span> <span v-if=“scope.row.sex===1”>女</span> </template> </el-table-column> </el-table> </el-main> <el-footer> <div style=“padding: 15px 0;text-align: right;”> <el-pagination background @size-change=“handleSizeChange” @current-change=“handleCurrentChange” :current-page=“formInline.pageNum” :page-sizes=“pageSizes” :page-size=“formInline.pageSize” layout=“total, sizes, prev, pager, next, jumper” :total=“pageTotal”> </el-pagination> </div> </el-footer> </el-container> </template> <script> import {commonAPI} from ‘@/api/commonAPI’ export default { data() { return { tableData: [], loading: false, formInline: { userName: ‘’, sex: ‘’, pageNum:1, pageSize:10 }, pageSizes:[5, 10, 15, 20], pageTotal:0 } }, created() { this.getData(); }, methods: { getData() { this.loading = true, commonAPI(‘queryUserList’,this.formInline) .then(res => { this.loading = false; this.tableData = res.data.data.rows; this.pageTotal=res.data.data.total; }) }, onSubmit() { this.getData(); }, resetting() { this.formInline.userName = ‘’; this.formInline.sex = ‘’; this.getData(); }, handleSizeChange(val) { //console.log(`每页 ${val} 条`); this.formInline.pageSize=val; this.formInline.pageNum=1; this.getData(); }, handleCurrentChange(val) { //console.log(`当前页: ${val}`); this.formInline.pageNum=val; this.getData(); } } } </script> <style scoped> .elInput, .btn { margin-top: 18px; } </style> <style> .el-main { padding: 5px 10px; } .elMain{ height: 418px; } .el-table th { height: 45px; font-size: 16px; font-family: 微软雅黑; font-weight: 500; color: darkblue; } </style>

3.5后端

按上面结构图,从上往下

3.5.1 SysAccessLogAspect.java

package com.wzz.aspect; import com.wzz.common.IDUtil; import com.wzz.common.StringUtil; import com.wzz.controller.SysAccessLogController; import com.wzz.service.ISysAccessLogService; import org.aspectj.lang.JoinPoint; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import javax.servlet.http.HttpServletRequest; import java.util.Arrays; import java.util.Date; import java.util.HashMap; import java.util.Map; /** * @ClassName SysAccessLogAspect * @Description TODO 系统访问日志切面类 * @Author zhengsongbo * Version 1.0 **/ @Component public class SysAccessLogAspect { @Autowired private HttpServletRequest request; @Autowired private ISysAccessLogService sysAccessLogService; //访问时间 private Date accessDate; //日志信息Map private Map<String,Object> logMap=new HashMap<>(); private Class clazz; //访问类 public void doBefore(JoinPoint jp){ clazz = jp.getTarget().getClass(); if (clazz!= SysAccessLogController.class) { //日志ID logMap.put(“logId”, IDUtil.getUUID()); String url = request.getRequestURL().toString(); //请求url logMap.put(“accessInterface”, url); String ip = request.getRemoteAddr(); //请求Ip logMap.put(“accessIp”, ip); String requestType = request.getMethod(); //请求方式 logMap.put(“requestType”, requestType); accessDate = new Date(); //访问时间 logMap.put(“accessDate”, accessDate); String args = Arrays.toString(jp.getArgs()); //方法参数 logMap.put(“interfaceParams”, args); String browserSystemInfo = StringUtil.getBrowserSystemInfo(request); //访问浏览器系统信息 logMap.put(“accessSource”, browserSystemInfo); } } public void doAfter(JoinPoint jp){ if (clazz!=SysAccessLogController.class){ long executeTime = new Date().getTime() - accessDate.getTime(); //执行时长 logMap.put(“executeTime”,executeTime); //插入日志信息 sysAccessLogService.saveSysLog(logMap); } } }

3.5.2 AssembleResponseMsg.java

package com.wzz.common; import com.wzz.model.InfoMsg; import com.wzz.model.ResponseBody; /** * @ClassName AssembleResponseMsg * @Description TODO 封装ResponseBody内容 * @Author zhengsongbo * Version 1.0 **/ public class AssembleResponseMsg { /** * 成功返回内容 * @Author zhengsongbo * @Param [data] * @return com.wzz.model.ResponseBody **/ public <T>ResponseBody success(T data){ ResponseBody<T> resp=new ResponseBody<T>(); resp.setData(data); InfoMsg info=new InfoMsg(); resp.setInfo(info); return resp; } /** * 失败/异常返回内容 * @Author zhengsongbo * @Param [status, errorCode, message] * @return com.wzz.model.ResponseBody **/ public <T>ResponseBody failure(int status,String errorCode,String message){ ResponseBody<T> resp=new ResponseBody<T>(); resp.setStatus(status); InfoMsg info=new InfoMsg(); info.setCode(errorCode); info.setMessage(message); resp.setInfo(info); return resp; } }

3.5.3 DateUtil.java

package com.wzz.common; import java.text.SimpleDateFormat; import java.util.Date; /** * @ClassName DateUtils * @Description TODO 日期工具类 * @Author zhengsongbo * Version 1.0 **/ public class DateUtil { /** * 返回字符串形式的当前日期 * @Author zhengsongbo * @Param [pattern] 模板参数 如:“yyyy-MM-dd” * @return java.lang.String **/ public static String getCurrentDateStr(String pattern){ SimpleDateFormat format=new SimpleDateFormat(pattern); String currentDateStr = format.format(new Date()); return currentDateStr; } }

3.5.4 IDUtil.java

package com.wzz.common; import java.util.UUID; /** * 各种ID工具类 * @ClassName IDUtil * @Description TODO * @Author zhengsongbo * Version 1.0 **/ public class IDUtil { /** * 获取uuid(以去掉’-'字符) * @Author zhengsongbo * @Param [] * @return java.lang.String **/ public static String getUUID(){ return UUID.randomUUID().toString().replace(“-”, “”); } }

3.5.5 StringUtil.java

package com.wzz.common; import eu.bitwalker.useragentutils.UserAgent; import javax.servlet.http.HttpServletRequest; /** * 字符串工具类 * @ClassName StringUtil * @Description TODO * @Author zhengsongbo * Version 1.0 **/ public class StringUtil { /** * 浏览器和系统信息 * @Author zhengsongbo * @Param [request] * @return java.lang.String **/ public static String getBrowserSystemInfo(HttpServletRequest request){ UserAgent userAgent = UserAgent.parseUserAgentString(request.getHeader(“user-agent”)); String BSInfo = userAgent.getOperatingSystem() + “-” + userAgent.getBrowser() + “(” + userAgent.getBrowserVersion() + “)”; return BSInfo; } }

3.5.6 SysAccessLogController.java

package com.wzz.controller; import com.wzz.common.AssembleResponseMsg; import com.wzz.model.ResponseBody; import com.wzz.service.ISysAccessLogService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import java.util.Map; /** * 系统访问日志Controller * @ClassName SysAccessLogController * @Description TODO * @Author zhengsongbo * Version 1.0 **/ @RestController public class SysAccessLogController { @Autowired private ISysAccessLogService sysAccessLogService; /** * 查询系统访问日志列表 * @Author zhengsongbo * @Param [map] * @return com.wzz.model.ResponseInfo **/ @RequestMapping(value = “/sysLogList”,produces = “application/json;charset=utf-8”) public ResponseBody querySysLogList(@RequestBody Map<String,Object> map){ Map<String, Object> resultMap = sysAccessLogService.querySysLogList(map); return new AssembleResponseMsg().success(resultMap); } }

3.5.7 UserController.java

package com.wzz.controller; import com.wzz.common.AssembleResponseMsg; import com.wzz.model.ResponseBody; import com.wzz.service.IUserService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import java.util.Map; /** * @ClassName UserController * @Description TODO 用户控制层 * @Author zhengsongbo * Version 1.0 **/ @RestController public class UserController { @Autowired private IUserService userService; @RequestMapping(value = “/queryUserList”,produces = “application/json;charset=utf-8”) public ResponseBody queryUserList(@RequestBody Map<String,Object> map){ Map<String, Object> resultMap = userService.queryUserList(map); return new AssembleResponseMsg().success(resultMap); } @RequestMapping(value = “/queryUser”,produces = “application/json;charset=utf-8”) public ResponseBody queryUser(@RequestBody Map<String,Object> map){ int flag = userService.queryUser(map); if (flag==1){ return new AssembleResponseMsg().success(“OK”); }{ return new AssembleResponseMsg().failure(200,“error”,“用户名或密码错误”); } } }

3.5.8 SysAccessLogMapper.java

package com.wzz.mapper; import java.util.List; import java.util.Map; /** * @Autor zhengsongbo * @Date 2020/12/7 16:58 **/ public interface SysAccessLogMapper { List<Map<String, Object>> querySysLogList(Map<String, Object> map); int saveSysLog(Map<String, Object> map); }

3.5.9 SysAccessLogMapper.xml

<?xml version=“1.0” encoding=“UTF-8” ?> <!DOCTYPE mapper PUBLIC “-//mybatis.org//DTD Mapper 3.0//EN” “http://mybatis.org/dtd/mybatis-3-mapper.dtd”> <mapper namespace=“com.wzz.mapper.SysAccessLogMapper”> <select id=“querySysLogList” parameterType=“map” resultType=“hashMap”> SELECT DATE_FORMAT(t.accessDate,‘%Y-%m-%d %H:%i:%s’) accessDate,t.requestType,t.accessInterface,t.interfaceParams,t.accessSource,t.accessIp,t.executeTime FROM tbsyslog t where t.accessDate&gt;=#{beginTime} and t.accessDate&lt;=#{endTime} order by t.accessDate DESC </select> <insert id=“saveSysLog” parameterType=“map”> insert into tbSysLog(logId,accessDate,requestType,accessInterface,interfaceParams,accessSource,accessIp,executeTime) values (#{logId},#{accessDate},#{requestType},#{accessInterface},#{interfaceParams},#{accessSource},#{accessIp},#{executeTime}) </insert> </mapper>

3.5.10 UserMapper.java

package com.wzz.mapper; import com.wzz.model.User; import java.util.List; import java.util.Map; /** * @Autor zhengsongbo * @Date 2020/12/7 15:36 **/ public interface UserMapper { List<User> queryUserList(Map<String, Object> map); //查询用户 int queryUser(Map<String, Object> map); }

3.5.11 UserMapper.xml

*<?*xml version=“1.0” encoding=“UTF-8” ?> <!DOCTYPE mapper PUBLIC “-//mybatis.org//DTD Mapper 3.0//EN” “http://mybatis.org/dtd/mybatis-3-mapper.dtd”> <mapper namespace=“com.wzz.mapper.UserMapper”> <!–因为在sqlMapConfig.xml中配置了别名,所以直接写user就可以–> <select id=“queryUserList” parameterType=“map” resultType=“user”> select * from tbUser <where> <if test=“userName!=null and userName!=‘’”> userName like CONCAT(‘%’,#{userName},‘%’) </if> <if test=“sex!=null and sex!=‘’”> AND sex=#{sex} </if> </where> </select> <select id=“queryUser” parameterType=“map” resultType=“int”> select count(1) from tbUser where userName=#{userName} and password=#{password} </select> </mapper>

3.5.12 InfoMsg.java

package com.wzz.model; import java.io.Serializable; /** * @ClassName InfoMsg * @Description TODO 错误信息消息体 * @Author zhengsongbo * Version 1.0 **/ public class InfoMsg implements Serializable { //自定义错误码 默认0表示正常执行 private String code=“0”; //错误信息 private String message=“操作成功”; public String getCode() { return code; } public void setCode(String code) { this.code = code; } public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } }

3.5.13 ResponseBody.java

package com.wzz.model; import com.wzz.common.DateUtil; import java.io.Serializable; /** * @ClassName ResponseBody * @Description TODO 封装响应的数据结构 * @Author zhengsongbo * Version 1.0 **/ public class ResponseBody<T> implements Serializable { //时间 private String date= DateUtil.getCurrentDateStr(“yyyy-MM-dd HH:mm:ss”); //状态码 默认200响应成功 private int status=200; //接口返回的数据 private T data; public String getDate() { return date; } public void setDate(String date) { this.date = date; } public int getStatus() { return status; } public void setStatus(int status) { this.status = status; } public T getData() { return data; } public void setData(T data) { this.data = data; } public InfoMsg getInfo() { return info; } public void setInfo(InfoMsg info) { this.info = info; } //消息内容 private InfoMsg info; }

3.5.14 User.java

package com.wzz.model; import java.io.Serializable; /** * @ClassName User * @Description TODO 用户类 * @Author zhengsongbo * Version 1.0 **/ public class User implements Serializable { Private Integer id; //用户标识 private String uid; //uid private String userName; //用户名 private String password; //密码 private String uName; //姓名 private Integer age; //年龄 private Integer sex; //性别 public String getUid() { return uid; } public void setUid(String uid) { this.uid = uid; } public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public String getuName() { return uName; } public void setuName(String uName) { this.uName = uName; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } public Integer getSex() { return sex; } public void setSex(Integer sex) { this.sex = sex; } @Override public String toString() { return “User{” + “uid='” + uid + ‘\’’ + “, userName='” + userName + ‘\’’ + “, password='” + password + ‘\’’ + “, uName='” + uName + ‘\’’ + “, age=” + age + “, sex=” + sex + ‘}’; } }

3.5.15 SysAccessLogServiceImpl.java

package com.wzz.service.impl; import com.github.pagehelper.PageHelper; import com.github.pagehelper.PageInfo; import com.wzz.mapper.SysAccessLogMapper; import com.wzz.service.ISysAccessLogService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.HashMap; import java.util.List; import java.util.Map; /** * 系统访问日志实现类 * @ClassName SysAccessLogServiceImpl * @Description TODO * @Author zhengsongbo * Version 1.0 **/ @Service public class SysAccessLogServiceImpl implements ISysAccessLogService { @Autowired private SysAccessLogMapper sysAccessLogMapper; @Override public Map<String, Object> querySysLogList(Map<String, Object> map) { int pageNum=Integer.parseInt(map.get(“pageNum”).toString()); //当前页 int pageSize=Integer.parseInt(map.get(“pageSize”).toString()); //每页几条 PageHelper.startPage(pageNum,pageSize); List<Map<String, Object>> resultList = sysAccessLogMapper.querySysLogList(map); PageInfo pageInfo=new PageInfo(resultList); long total = pageInfo.getTotal(); //总条数 Map<String,Object> resultMap=new HashMap<>(); resultMap.put(“total”,total); resultMap.put(“rows”,resultList); return resultMap; } @Override public int saveSysLog(Map<String, Object> map) { return sysAccessLogMapper.saveSysLog(map); } }

3.5.16 UserServiceImpl.java

package com.wzz.service.impl; import com.github.pagehelper.PageHelper; import com.github.pagehelper.PageInfo; import com.wzz.mapper.UserMapper; import com.wzz.model.User; import com.wzz.service.IUserService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.HashMap; import java.util.List; import java.util.Map; /** * @ClassName UserServiceImpl * @Description TODO 用户业务层实现类 * @Author zhengsongbo * Version 1.0 **/ @Service public class UserServiceImpl implements IUserService { @Autowired private UserMapper userMapper; @Override public Map<String,Object> queryUserList(Map<String, Object> map) { int pageNum=Integer.parseInt(map.get(“pageNum”).toString()); //当前页 int pageSize=Integer.parseInt(map.get(“pageSize”).toString()); //每页几条 PageHelper.startPage(pageNum,pageSize); List<User> userList = userMapper.queryUserList(map); PageInfo pageInfo=new PageInfo(userList); long total = pageInfo.getTotal(); Map<String,Object> resultMap=new HashMap<>(); resultMap.put(“total”,total); resultMap.put(“rows”,userList); return resultMap; } @Override public int queryUser(Map<String, Object> map) { return userMapper.queryUser(map); } }

3.5.17 ISysAccessLogService.java

package com.wzz.service; import java.util.Map; /** * @ClassName ISysAccessLogService * @Description TODO 系统访问日志接口 * @Autor zhengsongbo * @Date 2020/12/7 16:59 * @Version 1.0 **/ public interface ISysAccessLogService { /** * 查询系统日志列表 * @Author zhengsongbo * @Param [map] * @return java.util.Map<java.lang.String,java.lang.Object> **/ public Map<String,Object> querySysLogList(Map<String, Object> map); /** * 保存日志 * @Author zhengsongbo * @Param [map] * @return int **/ public int saveSysLog(Map<String, Object> map); }

3.5.18 IUserService.java

package com.wzz.service; import java.util.Map; /** * @ClassName IUserService * @Description TODO 用户业务层接口 * @Author zhengsongbo * Version 1.0 **/ public interface IUserService { Map<String,Object> queryUserList(Map<String, Object> map); int queryUser(Map<String, Object> map); }

三、功能小演示