当前位置:网站首页>Over 100000 words_ Ultra detailed SSM integration practice_ Manually implement permission management
Over 100000 words_ Ultra detailed SSM integration practice_ Manually implement permission management
2022-07-07 09:23:00 【I'm Bo Li Bo】
SSM Integrate _ Basic configuration
SSM The framework contains Spring,SpringMVC,Mybatis. and Spring And SpringMVC All are Spring Framework Module , No consolidation required . Just put the Mybatis And Spring Just integrate .
One 、 Integration concerns
1、Spring stay web Application in the project .
stay web When the project starts , Read applicationContext.xml The configuration file , establish IOC Containers .
2、 Use connection pool as data source .
Connect directly to the data source or Spring Data sources in (DriverManagerDataSource), Connection efficiency is too low . Use the Druid connection pool under Alibaba (druid) As a connection data source .
3、Mybatis And Spring The combination of .
adopt Spring Of IOC Container management SqlSessionFactory、mapper The proxy object of the interface .
Two 、 Import dependence
2.1 Spring rely on
<!-- spring Core packages -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>4.3.18.RELEASE</version>
</dependency>
<!-- springbean package -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>4.3.18.RELEASE</version>
</dependency>
<!-- springcontext package -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.3.18.RELEASE</version>
</dependency>
<!-- spring Expression package -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
<version>4.3.18.RELEASE</version>
</dependency>
<!-- springAOP package -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>4.3.18.RELEASE</version>
</dependency>
<!-- springAspects package -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>4.3.18.RELEASE</version>
</dependency>
<!-- springJDBC package -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>4.3.18.RELEASE</version>
</dependency>
<!-- spring Transaction package -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>4.3.18.RELEASE</version>
</dependency>
<!-- spring Yes web Support for -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>4.3.18.RELEASE</version>
</dependency>
<!-- springwebMVC -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>4.3.18.RELEASE</version>
</dependency>
2.2 Mybatis rely on
<!-- mybatis -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.6</version>
</dependency>
<!-- mybatis The paging assistant for -->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>5.1.2</version>
</dependency>
2.3 Mybatis And Spring Integration dependence
<!--Mybatis And Spring Integrated package -->
<!-- course : SSH: Spring Struts2 Hibernate And Hibernate/ibatis The integration package of is made up of Spring Provide ,spring-orm SSM: Spring SpringMVC Mybatis And Mybatis The integration package of is made up of Mybatis Provide ,mybatis-spring -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.3.2</version>
</dependency>
2.4 Connection pool and database driver depend
<!-- oracle drive -->
<dependency>
<groupId>com.oracle</groupId>
<artifactId>ojdbc6</artifactId>
<version>11.2.0</version>
</dependency>
<!-- mysql drive -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.49</version>
</dependency>
<!-- Connection pool : Druid data source -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.10</version>
</dependency>
2.5 JavaWeb Environment depends on
<!-- servlet-api -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<!-- jsp-api -->
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.1</version>
<scope>provided</scope>
</dependency>
<!-- jstl -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
2.6 Optional plug-in dependencies
<!-- Upload package -->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.1</version>
</dependency>
<!-- jackson -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.9.5</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.5</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.9.5</version>
</dependency>
<!-- hibernate The verification framework of -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>5.4.1.Final</version>
</dependency>
<!-- log4j -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<!-- junit-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
3、 ... and 、 Directory structure
src/main/java Create under directory Java Software package structure .
src/main/resources Various configuration files and resource files are stored in the directory .
webapp Store in the directory web Project static resources and WEB-INF Catalog , among jsp Pages are stored in WEB-INF Next .
Four 、 The configuration file
4.1 web.xml
<?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">
</web-app>
4.1.1 Character encoding filter
use Spring The character encoding filter provided in CharacterEncodingFilter.
<!-- Character encoding filter -->
<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>
4.1.2 IOC Monitor of container
stay web When the project starts , Context object ServletContext After object initialization , Read Spring And create IOC Container object , Finally, put it into the context scope .
use Spring Provided in ContextLoaderListener Monitor .
<!-- Initialization parameters of upper and lower objects -->
<context-param>
<param-name>contextConfigLocation</param-name>
<!-- Use wildcards * Load multiple profiles -->
<param-value>classpath:applicationContext*.xml</param-value>
</context-param>
<!-- springIOC Containers -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
4.1.3 Front controller
<!-- Configure front end controller -->
<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:springmvc.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>
4.1.4 The welcome page
<welcome-file-list>
<welcome-file>/WEB-INF/views/index.jsp</welcome-file>
</welcome-file-list>
4.1.5 Other configuration
<!-- This problem is solved by hiding the domain parameters form Form PUT And DELETE Method request -->
<filter>
<filter-name>HiddenHttpMethodFilter</filter-name>
<filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>HiddenHttpMethodFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- solve put The problem of requesting parameters -->
<filter>
<filter-name>HttpPutFormContentFilter</filter-name>
<filter-class>org.springframework.web.filter.HttpPutFormContentFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>HttpPutFormContentFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
4.2 Mybatis The configuration file
before mybatis-config.xml China needs load resources 、 Global parameter 、 Type the alias 、 Paging plug-ins 、 Connect to the database environment 、 Load mapping file Other configuration . But with Spring After integration , load resources 、 Connect to the database environment Must move into Spring Middle configuration , Load mapping file It is suggested to move into Spring in ( You can use wildcards ), The other two are ok . If you move everything into Spring Middle configuration , Then this file can disappear .
<?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>
<!-- Load external resource file : move Spring The configuration of ( The abolition of )-->
<!--<properties resource="db.properties"></properties>-->
<!-- Global parameter : You can move in Spring Configuration of -->
<settings>
<!-- Start the sliding line and turn to the hump -->
<setting name="mapUnderscoreToCamelCase" value="true"/>
<!-- Turn on mybatis SQL journal ,SSM After integration, there is no log output , It needs to be configured separately -->
<setting name="logImpl" value="org.apache.ibatis.logging.stdout.StdOutImpl"/>
</settings>
<!-- Type the alias : You can move in Spring Configuration of -->
<!--<typeAliases> <package name="com.newcapec.entity"/> </typeAliases>-->
<!-- plug-in unit : You can move in Spring Configuration of -->
<plugins>
<plugin interceptor="com.github.pagehelper.PageInterceptor">
<property name="reasonable" value="true"/>
</plugin>
</plugins>
<!-- Environmental Science : move Spring The configuration of ( The abolition of : Use third-party data source objects )-->
<!--<environments default="mysql"> <environment id="mysql"> <transactionManager type="JDBC"></transactionManager> <dataSource type="POOLED"> <property name="driver" value="${jdbc.mysql.driver}"/> <property name="url" value="${jdbc.mysql.url}"/> <property name="username" value="${jdbc.mysql.username}"/> <property name="password" value="${jdbc.mysql.password}"/> </dataSource> </environment> </environments>-->
<!-- Load mapping file : move Spring The configuration of ( The abolition of :Spring Can be loaded in batches mapper file ) -->
<!--<mappers> <mapper resource="mapper/EmpMapper.xml"/> </mappers>-->
</configuration>
db.properties:
#mysql
jdbc.mysql.driver=com.mysql.jdbc.Driver
jdbc.mysql.url=jdbc:mysql://localhost:3306/ssm?characterEncoding=utf8&useSSL=false
jdbc.mysql.username=root
jdbc.mysql.password=root
#oracle
jdbc.oracle.driver=oracle.jdbc.driver.OracleDriver
jdbc.oracle.url=jdbc:oracle:thin:@localhost:1521:orcl
jdbc.oracle.username=system
jdbc.oracle.password=123456
log4j.properties:
# A pound sign indicates a comment , The configuration content is in the format of key value pair , Each row can only have one key value pair , Between key value pairs = Connect
# Appoint logger
# Set up log4j Log level and destination of output
#INFO The level of logging ,Console and logfile The destination of the output
# Grade OFF,ERROR,WARN,INFO,DEBUG,TRACE,ALL
log4j.rootLogger=DEBUG,Console
# Appoint appender
# Set up Logger Of Console, among Console For custom name , The type is console output
log4j.appender.Console=org.apache.log4j.ConsoleAppender
# Set up Logger Of logfile, among logfile For custom name , The type is file
#org.apache.log4j.FileAppender file
#org.apache.log4j.RollingFileAppender When the file size reaches the specified size, a new file is generated
#org.apache.log4j.DailyRollingFileAppender Generate a log file every day
log4j.appender.logfile=org.apache.log4j.RollingFileAppender
# Set the output path of the file
log4j.appender.logfile.File=d:/log/test.log
# Set maximum file size Units can make KB,MB,GB
log4j.appender.logfile.MaxFileSize=2048KB
# Output format
# Set up appender Layout Layout
# %d Date and time of the output log , Specify the format :%d{yyyy-MM-dd HH:mm:ss SSS}
# %p Log level of output
# %c Output the full class name of the class
# %M Method name
# %m The message specified in the output code
# %n A line break
log4j.appender.Console.layout=org.apache.log4j.PatternLayout
log4j.appender.Console.layout.ConversionPattern=%d %p %c.%M() --%m%n
log4j.appender.logfile.layout=org.apache.log4j.PatternLayout
log4j.appender.logfile.layout.ConversionPattern=%d %p %c.%M() --%m%n
4.3 Spring The configuration file
because Spring Too many configurations in , Can be Spring It is divided into multiple files for separate configuration .
stay web.xml You can load them together through wildcards (classpath:spring/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:util="http://www.springframework.org/schema/util" xmlns:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
</beans>
4.3.1 applicationContext.xml
- Annotation scan :
To configure : The basic package is a public package (com.newcapec), And filter it out @Controller annotation .
Ideas :Spring And SpringMVC Scan their content separately ,SpingMVC Scan the classes of the presentation layer (Controller), and Spring Scan other .
<!-- Component scan ( Open component )-->
<context:component-scan base-package="com.newcapec">
<!-- Filter Controller annotation , stay SpringMVC scanning -->
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
- data source :
To configure : Read db.properties file , The data source object adopts the Druid connection pool under Alibaba , And configure the basic information of the connection database and the key information of the connection pool .
<!-- Import external resource file -->
<context:property-placeholder location="classpath:db.properties"/>
<!-- Configuration of data source : Druid connection pool -->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<!-- Basic configuration -->
<property name="driverClassName" value="${jdbc.mysql.driver}"/>
<property name="url" value="${jdbc.mysql.url}"/>
<property name="username" value="${jdbc.mysql.username}"/>
<property name="password" value="${jdbc.mysql.password}"/>
<!-- Key configuration -->
<!-- Number of physical connections established during initialization . Initialization occurs in the display call init Method , Or for the first time getConnection when -->
<property name="initialSize" value="${druid.initialSize}" />
<!-- Minimum number of connection pools -->
<property name="minIdle" value="${druid.minIdle}" />
<!-- Maximum number of connection pools -->
<property name="maxActive" value="${druid.maxActive}" />
<!-- Configure the timeout time for getting connection waiting -->
<property name="maxWait" value="${druid.maxWait}" />
</bean>
#mysql
jdbc.mysql.driver=com.mysql.jdbc.Driver
jdbc.mysql.url=jdbc:mysql://localhost:3306/ssm?characterEncoding=utf8&useSSL=false
jdbc.mysql.username=root
jdbc.mysql.password=root
#oracle
jdbc.oracle.driver=oracle.jdbc.driver.OracleDriver
jdbc.oracle.url=jdbc:oracle:thin:@localhost:1521:orcl
jdbc.oracle.username=system
jdbc.oracle.password=123456
#druid
druid.initialSize=5
druid.minIdle=5
druid.maxActive=15
druid.maxWait=10000
- Mybatis
To configure :SqlSessionFactory object bean and mapper The proxy object of the interface bean.
Ideas :
1、SqlSessionFactory The best use range of is the whole application running period , Once created, it can be reused , Usually managed in singleton mode . adopt mybatis-spring In the integration package SqlSessionFactoryBean To create a singleton SqlSessionFactory.
2、SqlSessionFactoryBean The property of must be configured with the data source , Optional loading Mybatis Global configuration file for ( If part of the content remains ), load mapper The mapping file ( It is recommended to configure , You can use the unified character to load in batches ), Type the alias , Plug in and other information .
3、Mybatis Medium mapper Proxy objects can be passed for each interface MapperFactoryBean To configure separately , Just tell Dao The fully qualified name of the interface . shortcoming : In large and medium-sized projects Dao When there are too many interfaces , Too much configuration , Not recommended .
4、 adopt MapperScannerConfigurer To configure mapper Agent scanners can be configured in batches mapper Proxy object , Just tell Dao The storage package name and SqlSessionFactory that will do .
<!--mybatis Configuration of : SqlSessionFactory factory = new SqlSessionFactoryBuilder().build( Read configuration file ) SqlSession sqlSession = factory.openSession(); StudentDao dao = sqlSession.getMapper(StudentDao.class) -->
<!--SqlSessionFactory object -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!-- Data source object -->
<property name="dataSource" ref="dataSource"/>
<!-- load mybatis Global configuration file for -->
<property name="configLocation" value="classpath:mybatis-config.xml"/>
<!-- load mapper file : Support wildcard batch loading , And you can specify any directory -->
<property name="mapperLocations" value="classpath:mapper/*Mapper.xml"/>
<!-- Type the alias -->
<!--<property name="typeAliasesPackage" value="com.newcapec.entity"/>-->
<!-- plug-in unit -->
<!--<property name="plugins"> <array> <bean class="com.github.pagehelper.PageInterceptor"> <property name="properties" value="reasonable=true"/> </bean> </array> </property>-->
<!-- Global parameter -->
<!--<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"/> </bean> </property>-->
</bean>
<!-- To configure mapper Proxy object @Mapper-->
<bean id="empDao" class="org.mybatis.spring.mapper.MapperFactoryBean">
<!-- The fully qualified name of the interface implemented by the proxy object -->
<property name="mapperInterface" value="com.newcapec.dao.EmpDao"/>
<property name="sqlSessionFactory" ref="sqlSessionFactory"/>
</bean>
<bean id="deptDao" class="org.mybatis.spring.mapper.MapperFactoryBean">
<property name="mapperInterface" value="com.newcapec.dao.DeptDao"/>
<property name="sqlSessionFactory" ref="sqlSessionFactory"/>
</bean>
<!-- To configure mapper Agent scanner @MapperScan-->
<!-- effect : 1. scanning dao Interface all packages 2. For all scanned dao Interface to create mapper Proxy object 3. Will all mapper The proxy object is placed IOC Containers -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<!-- scanning dao Basic package : Multiple packages can be separated by commas -->
<property name="basePackage" value="com.newcapec.dao"/>
<!-- Inject SqlSessionFactory object -->
<!--<property name="sqlSessionFactory" ref="sqlSessionFactory"/>-->
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
</bean>
mapper File template :
<?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="">
</mapper>
4.3.2 applicationContext-tx.xml
- Transaction Management Profile
To configure : Transaction manager object , Business , Transaction properties , Business entry point .
Ideas :
1、 Transaction related configurations are placed in this file , Separate from other configurations , Reduce the bloated configuration file , Convenient for later maintenance .
2、 Use of persistence layer Mybatis frame , The transaction manager uses JDBC The transaction manager of (DataSourceTransactionManager), And inject the data source object .
3、 The transaction attributes can be configured better and reasonably according to different needs .
4、 Transaction pointcuts pass transactions through AOP Is applied to the specified tangent expression .
<!-- Transaction manager -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!-- Inject data source -->
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- Business -->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<!-- Configure transaction properties -->
<tx:attributes>
<tx:method name="add*" isolation="READ_COMMITTED" rollback-for="java.lang.Exception"/>
<tx:method name="edit*" isolation="READ_COMMITTED" rollback-for="java.lang.Exception"/>
<tx:method name="remove*" isolation="READ_COMMITTED" rollback-for="java.lang.Exception"/>
<tx:method name="find*" propagation="SUPPORTS" read-only="true"/>
<tx:method name="query*" propagation="SUPPORTS" read-only="true"/>
<tx:method name="get*" propagation="SUPPORTS" read-only="true"/>
<!-- The name of the method to which the transaction attribute applies ,* Means all methods -->
<tx:method name="*"/>
</tx:attributes>
</tx:advice>
<!-- Business entry point -->
<aop:config>
<aop:pointcut id="exp" expression="execution(* com.newcapec.service..*Impl.*(..))"/>
<!-- Relate pointcut expressions to transactions -->
<aop:advisor advice-ref="txAdvice" pointcut-ref="exp"/>
</aop:config>
4.4 SpringMVC The configuration file
<?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:util="http://www.springframework.org/schema/util" xmlns:p="http://www.springframework.org/schema/p" 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/util http://www.springframework.org/schema/util/spring-util.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd">
</beans>
- Annotation scan
To configure : The basic package is the software package of the presentation layer .
Ideas :SpingMVC Only the classes responsible for scanning the presentation layer (Controller).
analysis :
SpingMVC Annotation scanning in also places the scanned object into IOC In the container . When web After the project is started, the first configuration is Spring Initialization of container , And then there was SpringMVC Front end controller for (DispatchServlet), When the configuration is complete DispatchServlet I'll be in Spring Create a new container in the container . Actually, these are two containers ,Spring As a parent container ,SpringMVC As a sub container ( Here's the picture ),SpringMVC The objects in the sub container can be accessed Spring Objects in the parent container , But objects in the parent container cannot access objects in the child container .
Usually in Service In the injection Dao, And then Controller Infuse Service, This means that as SpringMVC The child container of is the parent container that can be accessed Spring Object's , If you put Controller Injection into Service It must be impossible . Assume that Dao,Serive,Controller All in the same container , Then there is no problem with dependency injection between objects , But it must all be SpringMVC Sub containers of ( stay SpringMVC Scan all ). If Dao,Serive,Controller All put in Spring In the parent container of ( stay Spring Scan all ), And then SpringMVC There is no... In the container Controller object , So the mapping will not be found when loading the processor adapter Controller object , So... Will appear on the page 404 Error of .
<context:component-scan base-package="com.newcapec.controller"/>
- Annotation driven
<mvc:annotation-driven conversion-service="conversionService"/>
- view resolver
<!-- view resolver -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/views/"/>
<property name="suffix" value=".jsp"/>
</bean>
- Formatting and type conversion services
<bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
<property name="converters">
<set>
<bean class="com.newcapec.util.DateConverter"/>
</set>
</property>
</bean>
- Static resource processing
<mvc:default-servlet-handler/>
<mvc:resources mapping="/static/**" location="/WEB-INF/static/"/>
- Other configuration
<!-- File upload parser -->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!-- Set upload file size , The unit is byte , The size is 100MB -->
<property name="maxUploadSize" value="104857600"/>
<!-- Set the character encoding for uploading -->
<property name="defaultEncoding" value="utf-8"/>
<!-- Set cache size , The size is 10KB-->
<property name="maxInMemorySize" value="10240"/>
</bean>
<!-- Configure interceptors -->
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<!-- Exclude paths that are not blocked -->
<mvc:exclude-mapping path="/login"/>
<bean class="com.newcapec.intercepor.LoginInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
<!-- Complete interceptor configuration -->
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<!-- Dynamic page Jump request and static resource mapping request -->
<mvc:exclude-mapping path="/page/**"/>
<mvc:exclude-mapping path="/static/**"/>
<mvc:exclude-mapping path="/auth/login"/>
<bean class="com.newcapec.interceptor.LoginInterceptor"/>
</mvc:interceptor>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<mvc:exclude-mapping path="/page/login"/>
<mvc:exclude-mapping path="/page/index"/>
<mvc:exclude-mapping path="/static/**"/>
<mvc:exclude-mapping path="/auth/**"/>
<mvc:exclude-mapping path="/permission/findMenu"/>
<bean class="com.newcapec.interceptor.PermissionInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
SSM Integrate _ Synchronize cases
This case is only used to verify whether the configuration is correct , All cases and projects in the later stage , All adopt asynchronous implementation .
One 、 Table structure
-- Student list
CREATE TABLE `student` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(20) DEFAULT NULL,
`gender` varchar(20) DEFAULT NULL,
`major` varchar(20) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
-- data
INSERT INTO `student` VALUES (1, ' Xiao Ming ', '1', ' Software Engineering ');
INSERT INTO `student` VALUES (2, ' Xiaohong ', '0', ' Network engineering ');
INSERT INTO `student` VALUES (3, ' Little black ', '1', ' Information security ');
INSERT INTO `student` VALUES (4, ' The small white ', '0', ' Network engineering ');
INSERT INTO `student` VALUES (5, ' Zhang San ', '1', ' Software Engineering ');
INSERT INTO `student` VALUES (6, ' Li Si ', '0', ' Art design ');
INSERT INTO `student` VALUES (7, ' Wang Wu ', '1', ' Game design ');
INSERT INTO `student` VALUES (8, ' Horse six ', '1', ' Mobile Internet ');
Two 、 Entity class
The package name of the entity class is entity/domain. Table name as entity class name , The fields in the table are used as member variable names in the entity class .
notes : Name according to the actual naming rules .
/** * Student entity */
public class Student {
private Integer id;
private String name;
private String gender;
private String major;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
public String getMajor() {
return major;
}
public void setMajor(String major) {
this.major = major;
}
}
3、 ... and 、 Persistence layer
The persistence layer package is named dao. Persistence layer interface name naming convention : Entity class name +Dao.
Method naming conventions in the persistence layer :
insert newly added
update modify
delete Just delete
deleteBatch Batch deletion
select Batch query
selectById Just check
notes : There is a set of naming norms in enterprises , Not absolutely .
3.1 Interface
public interface StudentDao {
/* * How to add new students * @param student Add student data */
void insert(Student student);
/* * Modify students' methods * @param student Modify student data */
void update(Student student);
/* * according to id Single deletion method * @param id Delete the student's id */
void delete(Integer id);
/* * according to id Batch deletion method * @param ids Delete the student's id */
void deleteBatch(Integer[] ids);
/* * How to query students in batches * @param student Entities that contain conditional data for querying students * @return List<Student> Student data queried */
List<Student> select(Student student);
/* * according to id How to query students * @param id Student id * @return Student Student data queried */
Student selectById(Integer id);
}
3.2 Mapper file
<?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 Agent development requirements 1:namespace Be consistent with the fully qualified pathname of the interface -->
<mapper namespace="com.newcapec.dao.StudentDao">
<!--Mapper Agent development requirements 2: Labeled id The value is consistent with the method name in the interface -->
<!--Mapper Agent development requirements 3: Labeled parameterType The value is consistent with the method parameter in the interface -->
<!--Mapper Agent development requirements 4: Labeled resultType The value is consistent with the method return value in the interface -->
<insert id="insert" parameterType="com.newcapec.entity.Student" useGeneratedKeys="true" keyProperty="id">
insert into student(name, gender, major)
values (#{name}, #{gender}, #{major})
</insert>
<update id="update" parameterType="com.newcapec.entity.Student">
update student
<set>
<if test="name != null">
name = #{name},
</if>
<if test="gender != null">
gender = #{gender},
</if>
<if test="major != null">
major = #{major}
</if>
</set>
where id = #{id}
</update>
<delete id="delete" parameterType="java.lang.Integer">
delete
from student
where id = #{id}
</delete>
<delete id="deleteBatch" parameterType="java.lang.Integer">
delete from student where id in
<foreach collection="array" open="(" close=")" separator="," item="id">
#{id}
</foreach>
</delete>
<select id="select" parameterType="com.newcapec.entity.Student" resultType="com.newcapec.entity.Student">
select id, name, gender, major from student
<where>
<if test="name != null and name != ''">
name like concat('%', #{name}, '%')
</if>
<if test="gender != null and gender != ''">
gender = #{gender}
</if>
<if test="major != null and major != ''">
major like concat('%', #{major}, '%')
</if>
</where>
</select>
<select id="selectById" parameterType="java.lang.Integer" resultType="com.newcapec.entity.Student">
select id, name, gender, major
from student
where id = #{id}
</select>
</mapper>
Four 、 The business layer
The business layer package is named service. Business layer interface name naming specification : Entity class +Service.
Method naming conventions in the business layer :
add newly added
edit edit
remove Delete
remove Batch deletion
find Batch query
findById Single query
service Layer naming and dao Layer naming :
1、 Later, the business becomes more and more complex , It is easy to distinguish by method name .
2、 For standard Spring Transaction configuration .
4.1 Interface
public interface StudentService {
void add(Student student);
void edit(Student student);
void remove(Integer id);
void removeBatch(Integer[] ids);
List<Student> find(Student student);
PageInfo findPage(Integer pageNum, Integer pageSize, Student student);
Student findById(Integer id);
}
4.2 Implementation class
@Service
public class StudentServiceImpl implements StudentService {
@Autowired
private StudentDao studentDao;
@Override
public void add(Student student) {
studentDao.insert(student);
}
@Override
public void edit(Student student) {
studentDao.update(student);
}
@Override
public void remove(Integer id) {
studentDao.delete(id);
}
@Override
public void removeBatch(Integer[] ids) {
studentDao.deleteBatch(ids);
}
@Override
public List<Student> find(Student student) {
return studentDao.select(student);
}
@Override
public PageInfo findPage(Integer pageNum, Integer pageSize, Student student) {
// Paging business implementation
PageHelper.startPage(pageNum, pageSize);
List<Student> list = studentDao.select(student);
PageInfo<Student> pageInfo = new PageInfo<>(list);
return pageInfo;
}
@Override
public Student findById(Integer id) {
return studentDao.selectById(id);
}
}
5、 ... and 、web layer
web The layer package is named controller. The naming convention of the class : Entity class name +Controller.
Synchronous request processing : Yes HTTP Limit GET( Query and delete ) and POST( Add and modify ).
@Controller
@RequestMapping("/student")
public class StudentController {
@Autowired
private StudentService studentService;
/* * newly added */
@PostMapping("/add")
public String add(Student student) {
studentService.add(student);
return "redirect:/student/find";
}
/* * modify */
@PostMapping("/edit")
public String edit(Student student) {
studentService.edit(student);
return "redirect:/student/find";
}
/* * Delete */
@GetMapping("/remove/{id}")
public String remove(@PathVariable Integer id) {
studentService.remove(id);
return "redirect:/student/find";
}
/* * Batch deletion */
@GetMapping("/remove")
public String removeBatch(Integer[] ids) {
studentService.removeBatch(ids);
return "redirect:/student/find";
}
/* * Single query */
@GetMapping("/find/{id}")
public String findById(@PathVariable Integer id, Model model) {
Student student = studentService.findById(id);
model.addAttribute("student", student);
// Jump to modify the student's view
return "stu/edit";
}
/* * Paging query * @param pageNum Page number * @param pageSize Number of entries per page * @param student Entities containing query criteria * @param model Used to direct to request Domain stores data ui * @return java.lang.String Jump to the view of the student list page * * The request received did not pageNum, The default value is 1 * The request received did not pageSize, The default value is 5 */
@GetMapping("/find")
public String findPage(@RequestParam(value = "pageNum", required = false, defaultValue = "1") Integer pageNum,
@RequestParam(value = "pageSize", required = false, defaultValue = "5") Integer pageSize,
Student student, Model model) {
PageInfo pageInfo = studentService.findPage(pageNum, pageSize, student);
model.addAttribute("pageInfo", pageInfo);
return "stu/list";
}
}
6、 ... and 、 Front page implementation
6.1 home page
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<base href="${pageContext.request.contextPath}/">
<title>Title</title>
</head>
<body>
<div style="text-align: center">
<h1> This is the home page </h1>
<a href="student/find"> Student information management </a>
</div>
</body>
</html>
6.2 Student list page
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<base href="${pageContext.request.contextPath}/">
<title>Title</title>
<style>
.container {
width: 600px;
margin: auto;
}
.container > h1 {
text-align: center;
}
table {
width: 100%;
border-collapse: collapse;
}
table, td, th {
border: 1px solid black;
}
tr {
height: 36px;
}
tr td:nth-child(1) {
text-align: center;
}
.pager {
text-align: center;
padding: 10px 0;
}
</style>
</head>
<body>
<div class="container">
<h1> Student data list </h1>
<p>
<%-- No direct access WEB-INF The following resources , Need to pass through Controller transit --%>
<%--<a href="WEB-INF/views/stu/add.jsp"> New students </a>--%>
<a href="page/stu/add"> New students </a>  
<a href="javascript:removeBatch();"> Batch deletion </a>
</p>
<%-- With the help of form Forms can be deleted synchronously in batches --%>
<form action="student/remove" method="GET" id="removeForm">
<table>
<thead>
<tr>
<th><input type="checkbox"></th>
<th> The student's name </th>
<th> Student gender </th>
<th> departments / major </th>
<th> operation </th>
</tr>
</thead>
<tbody>
<c:forEach items="${pageInfo.list}" var="student">
<tr>
<td><input type="checkbox" name="ids" value="${student.id}"></td>
<td>${student.name}</td>
<td>${student.gender == '1'?' male ':' Woman '}</td>
<td>${student.major}</td>
<td>
<a href="student/find/${student.id}"> modify </a>  
<a href="student/remove/${student.id}" οnclick="return confirm(' Are you sure you want to delete this data ?')"> Delete </a>
</td>
</tr>
</c:forEach>
</tbody>
</table>
</form>
<div class="pager">
The current page / Total number of pages : ${pageInfo.pageNum}/${pageInfo.pages}
<c:if test="${pageInfo.hasPreviousPage}">
<a href="student/find?pageNum=${pageInfo.prePage}"> The previous page </a>
</c:if>
<c:forEach begin="1" end="${pageInfo.pages}" var="p">
<c:if test="${pageInfo.pageNum != p}">
<a href="student/find?pageNum=${p}">【${p}】</a>
</c:if>
<c:if test="${pageInfo.pageNum == p}">
【${p}】
</c:if>
</c:forEach>
<c:if test="${pageInfo.hasNextPage}">
<a href="student/find?pageNum=${pageInfo.nextPage}"> The next page </a>
</c:if>
</div>
</div>
<script type="text/javascript" src="static/js/jquery-3.3.1.min.js"></script>
<script type="text/javascript">
function removeBatch() {
console.log($)
if ($(":checkbox:checked").length > 0) {
if (confirm(" Are you sure you want to delete the data ?")) {
$("#removeForm").get(0).submit();
}
} else {
alert(" Please select the student to delete !")
}
}
</script>
</body>
</html>
SystemController.java:
/** * The processor used to realize page Jump */
@Controller
@RequestMapping("/page")
public class SystemController {
@GetMapping("/stu/add")
public String stuAdd() {
return "stu/add";
}
}
6.3 New page
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<base href="${pageContext.request.contextPath}/">
<title>Title</title>
<style>
.container {
width: 600px;
margin: auto;
}
.container > h1 {
text-align: center;
}
</style>
</head>
<body>
<div class="container">
<h1> New student page </h1>
<form action="student/add" method="POST">
<p>
<label for="name"> The student's name :</label>
<input type="text" name="name" id="name" placeholder=" Please enter the student's name ">
</p>
<p>
<label> Student gender :</label>
<input type="radio" name="gender" value="1"> male
<input type="radio" name="gender" value="0"> Woman
</p>
<p>
<label for="major"> departments / major :</label>
<input type="text" name="major" id="major" placeholder=" Please enter the Department / major ">
</p>
<p>
<button type="submit"> newly added </button>
<button type="reset"> Reset </button>
</p>
</form>
</div>
</body>
</html>
6.4 Modify page
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<base href="${pageContext.request.contextPath}/">
<title>Title</title>
<style>
.container {
width: 600px;
margin: auto;
}
.container > h1 {
text-align: center;
}
</style>
</head>
<body>
<div class="container">
<h1> Students modify the page </h1>
<form action="student/edit" method="POST">
<input type="hidden" name="id" value="${student.id}">
<p>
<label for="name"> The student's name :</label>
<input type="text" name="name" id="name" placeholder=" Please enter the student's name " value="${student.name}">
</p>
<p>
<label> Student gender :</label>
<input type="radio" name="gender" value="1" <c:if test="${student.gender == '1'}">checked</c:if>> male
<input type="radio" name="gender" value="0" <c:if test="${student.gender == '0'}">checked</c:if>> Woman
</p>
<p>
<label for="major"> departments / major :</label>
<input type="text" name="major" id="major" placeholder=" Please enter the Department / major " value="${student.major}">
</p>
<p>
<button type="submit"> Confirm modification </button>
<button type="reset"> Reset </button>
</p>
</form>
</div>
</body>
</html>
SSM Integrate _ Asynchronous case
One 、 Table structure
-- ----------------------------
-- Permissions on the table
-- ----------------------------
DROP TABLE IF EXISTS `t_sys_permission`;
CREATE TABLE `t_sys_permission` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'id',
`name` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT ' Permission to name ',
`type` char(1) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT ' Authority type :1 Catalog 2 menu 3 Button ',
`url` varchar(200) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '#' COMMENT ' Access address ',
`percode` varchar(200) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT ' Authority code ',
`parent_id` int(11) NULL DEFAULT 0 COMMENT ' Parent node ID',
`sort` int(11) NULL DEFAULT NULL COMMENT ' According to the order ',
`del` char(1) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '0' COMMENT ' Whether or not to delete :0 normal 1 Delete ',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 14 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = ' Permission information table ' ROW_FORMAT = Dynamic;
-- ----------------------------
-- Permission table data
-- ----------------------------
INSERT INTO `t_sys_permission` VALUES (1, ' System management ', '1', '', 'system', 0, 1, '0');
INSERT INTO `t_sys_permission` VALUES (2, ' User list ', '2', '', 'user', 1, 11, '0');
INSERT INTO `t_sys_permission` VALUES (3, ' User query ', '3', '', 'user:query', 2, 111, '0');
INSERT INTO `t_sys_permission` VALUES (4, ' New users ', '3', '', 'user:add', 2, 112, '0');
INSERT INTO `t_sys_permission` VALUES (5, ' User edit ', '3', '', 'user:edit', 2, 113, '0');
INSERT INTO `t_sys_permission` VALUES (6, ' User deletion ', '3', '', 'user:remove', 2, 114, '0');
INSERT INTO `t_sys_permission` VALUES (7, ' Character list ', '2', '', 'role', 1, 12, '0');
INSERT INTO `t_sys_permission` VALUES (8, ' Role search ', '3', '', 'role:query', 7, 121, '0');
INSERT INTO `t_sys_permission` VALUES (9, ' Role addition ', '3', '', 'role:add', 7, 122, '0');
INSERT INTO `t_sys_permission` VALUES (10, ' Role editor ', '3', '', 'role:edit', 7, 123, '0');
INSERT INTO `t_sys_permission` VALUES (11, ' Character delete ', '3', '', 'role:remove', 7, 124, '0');
INSERT INTO `t_sys_permission` VALUES (12, ' Permission list ', '2', '', 'permission', 1, 13, '0');
INSERT INTO `t_sys_permission` VALUES (13, ' Permission query ', '3', '', 'permission:query', 12, 131, '0');
INSERT INTO `t_sys_permission` VALUES (14, ' New permission ', '3', '', 'permission:add', 12, 132, '0');
INSERT INTO `t_sys_permission` VALUES (15, ' Permission edit ', '3', '', 'permission:edit', 12, 133, '0');
INSERT INTO `t_sys_permission` VALUES (16, ' Permission deletion ', '3', '', 'permission:remove', 12, 134, '0');
-- ----------------------------
-- Role table
-- ----------------------------
DROP TABLE IF EXISTS `t_sys_role`;
CREATE TABLE `t_sys_role` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'id',
`role_code` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT ' Character encoding ',
`role_name` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT ' Character name ',
`description` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT ' describe ',
`del` char(1) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '0' COMMENT ' Whether or not to delete :0 normal 1 Delete ',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = ' Role information sheet ' ROW_FORMAT = Dynamic;
-- ----------------------------
-- Role table data
-- ----------------------------
INSERT INTO `t_sys_role` VALUES (1, 'admin', ' Administrators ', ' Administrators ', '0');
INSERT INTO `t_sys_role` VALUES (2, 'user', ' Ordinary users ', ' Ordinary users ', '0');
-- ----------------------------
-- Role authority middle table
-- ----------------------------
DROP TABLE IF EXISTS `t_sys_role_permission`;
CREATE TABLE `t_sys_role_permission` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT ' Primary key ',
`role_id` int(11) NOT NULL COMMENT ' role ID',
`permission_id` int(11) NOT NULL COMMENT ' jurisdiction ID',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 18 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = ' Role and permission association table ' ROW_FORMAT = Dynamic;
-- ----------------------------
-- Role permission intermediate table data
-- ----------------------------
INSERT INTO `t_sys_role_permission` VALUES (1, 1, 1);
INSERT INTO `t_sys_role_permission` VALUES (2, 1, 2);
INSERT INTO `t_sys_role_permission` VALUES (3, 1, 3);
INSERT INTO `t_sys_role_permission` VALUES (4, 1, 4);
INSERT INTO `t_sys_role_permission` VALUES (5, 1, 5);
INSERT INTO `t_sys_role_permission` VALUES (6, 1, 6);
INSERT INTO `t_sys_role_permission` VALUES (7, 1, 7);
INSERT INTO `t_sys_role_permission` VALUES (8, 1, 8);
INSERT INTO `t_sys_role_permission` VALUES (9, 1, 9);
INSERT INTO `t_sys_role_permission` VALUES (10, 1, 10);
INSERT INTO `t_sys_role_permission` VALUES (11, 1, 11);
INSERT INTO `t_sys_role_permission` VALUES (12, 1, 12);
INSERT INTO `t_sys_role_permission` VALUES (13, 1, 13);
INSERT INTO `t_sys_role_permission` VALUES (14, 2, 1);
INSERT INTO `t_sys_role_permission` VALUES (15, 2, 2);
INSERT INTO `t_sys_role_permission` VALUES (16, 2, 6);
INSERT INTO `t_sys_role_permission` VALUES (17, 2, 10);
-- ----------------------------
-- User table
-- ----------------------------
DROP TABLE IF EXISTS `t_sys_user`;
CREATE TABLE `t_sys_user` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT ' Primary key ',
`username` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT ' Login account ',
`mobile` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT ' Phone number ',
`nickname` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT ' The user nickname ',
`email` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT ' User mailbox ',
`userpwd` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT ' password ',
`salt` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT 'newedu' COMMENT ' Encrypting salt ',
`status` char(1) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '1' COMMENT ' state :1 You can use 2 Unavailable ',
`del` char(1) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '0' COMMENT ' Whether or not to delete :0 normal 1 Delete ',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = ' User information sheet ' ROW_FORMAT = Dynamic;
-- ----------------------------
-- User table data
-- ----------------------------
INSERT INTO `t_sys_user` VALUES (1, 'admin', '13612345678', ' Administrators ', '[email protected]', '8f32e9f68d6886d095b230b93e7a2c86', 'newedu', '1', '0');
INSERT INTO `t_sys_user` VALUES (2, 'tom', '12345678901', ' Tom ', '[email protected]', '8f32e9f68d6886d095b230b93e7a2c86', 'newedu', '1', '0');
-- ----------------------------
-- User role middle table
-- ----------------------------
DROP TABLE IF EXISTS `t_sys_user_role`;
CREATE TABLE `t_sys_user_role` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT ' Primary key ',
`user_id` int(11) NOT NULL COMMENT ' user ID',
`role_id` int(11) NOT NULL COMMENT ' role ID',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 4 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = ' User and role association table ' ROW_FORMAT = Dynamic;
-- ----------------------------
-- User role middle table data
-- ----------------------------
INSERT INTO `t_sys_user_role` VALUES (1, 1, 1);
INSERT INTO `t_sys_user_role` VALUES (2, 1, 2);
INSERT INTO `t_sys_user_role` VALUES (3, 2, 2);
Two 、 Basic packaging
2.1 System code
package com.newcapec.constant;
/* * System code : No Http Response code of the Protocol , It is our customized response code for some situations * effect : When the background responds to the front , In addition to the response data , Also respond to some coding , Through these codes, the front end can judge whether the operation is successful , Or failure , And the reasons for the failure . * For example, the user name and password are not code errors , It just doesn't match the corresponding data , But from a business perspective, it's wrong , We can respond to the specified code to inform the front end of the problem . * */
public enum SystemCode {
OK(200, " success "),
USERNAME_EXISTS(401, " User name already exists "),
USERNAME_ERROR(402, " Wrong user name or password "),
NO_USER(403, " The user doesn't exist "),
NOT_LOGIN(404, " The user is not logged in "),
NO_PERMISSION(405, " Insufficient authority , Blocking access "),
ERROR(500, " Failure ");
int code;
String message;
SystemCode(int code, String message) {
this.code = code;
this.message = message;
}
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
2.2 Common constant
package com.newcapec.constant;
/** * Common constant , Try to avoid constant values in the system , Cause difficulties in later maintenance . * such as : Before Controller As defined in pageNum,pageSize Are constant values , If you want to change the name later , All must be modified , Not conducive to maintenance . */
public class CommonConstant {
/* * Page name */
public static final String PAGE_NUM = "pageNum";
/* * Number of entries per page name */
public static final String PAGE_SIZE = "pageSize";
/* * Name of total records */
public static final String PAGE_TOTAL = "total";
/* * Data name of each page */
public static final String PAGE_LIST = "list";
/* * Page number defaults */
public static final String PAGE_NUM_DEFAULT = "1";
/* * The default value of entries per page */
public static final String PAGE_SIZE_DEFAULT = "10";
/* * Default password */
public static final String PASSWORD_DEFAULT = "123456";
}
2.3 Response format class
package com.newcapec.utils;
import com.newcapec.constant.SystemCode;
/** * Response format class * effect : Unify the response data format of the server */
public class Result<T> {
/** * Response code */
private int code;
/** * Response information */
private String message;
/** * The response data */
private T data;
public Result(int code, String message, T data) {
this.code = code;
this.message = message;
this.data = data;
}
/** * A successful response : Do not transfer data to the page */
public static Result success() {
return new Result(SystemCode.OK.getCode(), SystemCode.OK.getMessage(), null);
}
/** * A successful response : Transfer data to the page */
public static <T> Result success(T data) {
return new Result(SystemCode.OK.getCode(), SystemCode.OK.getMessage(), data);
}
/** * Failed response : Do not transfer data to the page */
public static Result error() {
return new Result(SystemCode.ERROR.getCode(), SystemCode.ERROR.getMessage(), null);
}
/** * Failed response : Transfer data to the page */
public static <T> Result error(T data) {
return new Result(SystemCode.ERROR.getCode(), SystemCode.ERROR.getMessage(), data);
}
/** * Failed response : Transfer data to the page , And pass the response code and response information */
public static <T> Result error(int code, String message, T data) {
return new Result(code, message, data);
}
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
}
2.4 Persistence layer public interface
package com.newcapec.utils;
import java.util.List;
/* * Persistence layer public interface */
public interface BaseDao<T> {
/* * The new method */
void insert(T entity);
/* * Modification method */
void update(T entity);
/* * according to id Single deletion method */
void delete(Integer id);
/* * according to id Batch deletion method */
void deleteBatch(Integer[] ids);
/* * Batch query method */
List<T> select(T entity);
/* * according to id How to query */
T selectById(Integer id);
}
2.5 Business layer public interface
package com.newcapec.utils;
import java.util.List;
import java.util.Map;
/* * Business layer public interface */
public interface BaseService<T> {
void add(T entity);
void edit(T entity);
void remove(Integer id);
void removeBatch(Integer[] ids);
List<T> find(T entity);
/* * In the synchronization case : Paging condition query , Our feedback is PageInfo object * however PageHelper It is recommended not to cross layers , For later maintenance . * such as : Later we passed Mybatis-plus Replace mybatis, So if cross layer , It needs to be changed in many places . */
Map<String, Object> findPage(Integer pageNum, Integer pageSize, T entity);
T findById(Integer id);
}
3、 ... and 、 System user module
3.1 Entity class
package com.newcapec.entity;
/** * System user entity class : Basic functions for user table CURD Implementation of operations */
public class SysUser {
private Integer id;
private String username;
private String mobile;
private String nickname;
private String email;
private String userpwd;
private String salt;
private String status;
private String del;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getMobile() {
return mobile;
}
public void setMobile(String mobile) {
this.mobile = mobile;
}
public String getNickname() {
return nickname;
}
public void setNickname(String nickname) {
this.nickname = nickname;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getUserpwd() {
return userpwd;
}
public void setUserpwd(String userpwd) {
this.userpwd = userpwd;
}
public String getSalt() {
return salt;
}
public void setSalt(String salt) {
this.salt = salt;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
public String getDel() {
return del;
}
public void setDel(String del) {
this.del = del;
}
}
3.2 Persistence layer
Dao Interface :
package com.newcapec.dao;
import com.newcapec.entity.SysUser;
import com.newcapec.utils.BaseDao;
/* * Inherit BaseDao The method defined in , It can also be extended . */
public interface SysUserDao extends BaseDao<SysUser> {
/* * Query according to user name * 1、 register : Duplicate user name check * 2、 The user login ( Refinement prompt use , First judge the user name , Then judge the password ) */
SysUser selectByUsername(String username);
}
Mapper file :
<?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.newcapec.dao.SysUserDao">
<insert id="insert" parameterType="com.newcapec.entity.SysUser" useGeneratedKeys="true" keyProperty="id">
insert into t_sys_user(username, mobile, nickname, email, userpwd, salt)
values (#{username}, #{mobile}, #{nickname}, #{email}, #{userpwd}, #{salt})
</insert>
<update id="update" parameterType="com.newcapec.entity.SysUser">
update t_sys_user
<set>
<if test="username != null">
username = #{username},
</if>
<if test="mobile != null">
mobile = #{mobile},
</if>
<if test="nickname != null">
nickname = #{nickname},
</if>
<if test="email != null">
email = #{email},
</if>
<if test="userpwd != null">
userpwd = #{userpwd},
</if>
<if test="salt != null">
salt = #{salt},
</if>
<if test="status != null">
status = #{status}
</if>
</set>
where id = #{id}
</update>
<delete id="delete" parameterType="java.lang.Integer">
update t_sys_user
set del = 1
where id = #{id}
</delete>
<delete id="deleteBatch" parameterType="java.lang.Integer">
update t_sys_user set del = 1 where id in
<foreach collection="array" open="(" close=")" separator="," item="id">
#{id}
</foreach>
</delete>
<resultMap id="BaseResultMap" type="com.newcapec.entity.SysUser">
<id column="id" property="id"/>
<result column="username" property="username"/>
<result column="mobile" property="mobile"/>
<result column="nickname" property="nickname"/>
<result column="email" property="email"/>
<result column="userpwd" property="userpwd"/>
<result column="salt" property="salt"/>
<result column="status" property="status"/>
</resultMap>
<select id="select" parameterType="com.newcapec.entity.SysUser" resultMap="BaseResultMap">
select id, username, mobile, nickname, email, userpwd, salt, status from t_sys_user
<where>
<if test="username != null and username != ''">
username like concat('%',#{username},'%')
</if>
<if test="nickname != null and nickname != ''">
and nickname like concat('%',#{nickname},'%')
</if>
and del=0
</where>
</select>
<select id="selectById" parameterType="java.lang.Integer" resultType="com.newcapec.entity.SysUser">
select id, username, mobile, nickname, email, userpwd, salt, status from t_sys_user
where id = #{id} and del=0
</select>
<select id="selectByUsername" parameterType="java.lang.String" resultType="com.newcapec.entity.SysUser">
select id, username, mobile, nickname, email, userpwd, salt from t_sys_user
where username = #{username} and del=0
</select>
</mapper>
3.3 The business layer
Service Interface :
package com.newcapec.service;
import com.newcapec.entity.SysUser;
import com.newcapec.utils.BaseService;
public interface SysUserService extends BaseService<SysUser> {
SysUser findByUsername(String username);
}
Service Interface implementation class :
package com.newcapec.service.impl;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.newcapec.constant.CommonConstant;
import com.newcapec.dao.SysUserDao;
import com.newcapec.entity.Student;
import com.newcapec.entity.SysUser;
import com.newcapec.service.SysUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Service
public class SysUserServiceImpl implements SysUserService {
@Autowired
private SysUserDao sysUserDao;
@Override
public SysUser findByUsername(String username) {
return sysUserDao.selectByUsername(username);
}
@Override
public void add(SysUser entity) {
SysUser sysUser = findByUsername(entity.getUsername());
// Background verification , Guarantee safety , Prevent third-party tools from registering (PostMan)
if (sysUser == null) {
entity.setUserpwd(CommonConstant.PASSWORD_DEFAULT);
sysUserDao.insert(entity);
}
}
@Override
public void edit(SysUser entity) {
SysUser sysUser = findByUsername(entity.getUsername());
if (sysUser != null) {
sysUserDao.update(entity);
}
}
@Override
public void remove(Integer id) {
sysUserDao.delete(id);
}
@Override
public void removeBatch(Integer[] ids) {
sysUserDao.deleteBatch(ids);
}
@Override
public List<SysUser> find(SysUser entity) {
return sysUserDao.select(entity);
}
@Override
public Map<String, Object> findPage(Integer pageNum, Integer pageSize, SysUser entity) {
// Paging business implementation
PageHelper.startPage(pageNum, pageSize);
List<SysUser> list = sysUserDao.select(entity);
PageInfo<SysUser> pageInfo = new PageInfo<>(list);
/* * Feed back the data needed by the front desk * 1、 Current page data ( Data list ) * 2、 Total records of this query */
Map<String, Object> pageMap = new HashMap<>();
pageMap.put(CommonConstant.PAGE_LIST, list);
pageMap.put(CommonConstant.PAGE_TOTAL, pageInfo.getTotal());
return pageMap;
}
@Override
public SysUser findById(Integer id) {
return sysUserDao.selectById(id);
}
}
3.4 Control layer
package com.newcapec.controller;
import com.newcapec.constant.CommonConstant;
import com.newcapec.constant.SystemCode;
import com.newcapec.entity.SysUser;
import com.newcapec.service.SysUserService;
import com.newcapec.utils.Result;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/user")
public class SysUserController {
@Autowired
private SysUserService sysUserService;
/** * newly added */
@PostMapping("/add")
public Result add(@RequestBody SysUser sysUser) {
sysUserService.add(sysUser);
return Result.success();
}
/** * edit */
@PutMapping("/edit")
public Result edit(@RequestBody SysUser sysUser) {
sysUserService.edit(sysUser);
return Result.success();
}
/** * Delete */
@DeleteMapping("/remove/{id}")
public Result remove(@PathVariable Integer id) {
sysUserService.remove(id);
return Result.success();
}
/** * Batch deletion */
@DeleteMapping("/remove")
public Result removeBatch(Integer[] ids) {
sysUserService.removeBatch(ids);
return Result.success();
}
/** * Single query */
@GetMapping("/find/{id}")
public Result findById(@PathVariable Integer id) {
return Result.success(sysUserService.findById(id));
}
/** * Paging query */
@GetMapping("/find")
public Result findPage(@RequestParam(value = CommonConstant.PAGE_NUM, required = false, defaultValue = CommonConstant.PAGE_NUM_DEFAULT) Integer pageNum,
@RequestParam(value = CommonConstant.PAGE_SIZE, required = false, defaultValue = CommonConstant.PAGE_SIZE_DEFAULT) Integer pageSize,
SysUser sysUser) {
return Result.success(sysUserService.findPage(pageNum, pageSize, sysUser));
}
/** * Determine if the user name is duplicate */
@GetMapping("/findExists/{username}")
public Result findUsernameExists(@PathVariable String username) {
SysUser sysUser = sysUserService.findByUsername(username);
if (sysUser == null) {
return Result.success();
}
return Result.error(SystemCode.USERNAME_EXISTS.getCode(), SystemCode.USERNAME_EXISTS.getMessage(), null);
}
}
3.5 test
All queries are Get request , You can test directly through the browser .
But increase 、 Delete 、 Change , The background programmer test can pass Postman.
Batch query test :
Single query test ( Path parameter ):
Paging query test ( Path parameter splicing ):
New test :
Revision Test :
Single delete test :
Batch delete test :
3.6 Foreground page
3.6.1 home page
be based on Layui Classic layout revision .
Address :https://www.layuion.com/doc/element/layout.html#admin
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<base href="${pageContext.request.contextPath}/">
<title> Background management system </title>
<!-- introduce Layui The style file -->
<link rel="stylesheet" href="static/layui/css/layui.css">
</head>
<body>
<!-- introduce layui Classic layout and revision -->
<div class="layui-layout layui-layout-admin">
<!-- Page header -->
<div class="layui-header">
<div class="layui-logo layui-hide-xs layui-bg-black"> Background management system </div>
<ul class="layui-nav layui-layout-right">
<li class="layui-nav-item layui-hide layui-show-md-inline-block">
<a href="javascript:;">
<img src="//tva1.sinaimg.cn/crop.0.0.118.118.180/5db11ff4gw1e77d3nqrv8j203b03cweg.jpg"
class="layui-nav-img">
Administrators
</a>
<dl class="layui-nav-child">
<dd><a href=""> Personal information </a></dd>
<dd><a href=""> System settings </a></dd>
<dd><a href=""> Exit the system </a></dd>
</dl>
</li>
</ul>
</div>
<div class="layui-side layui-bg-black">
<div class="layui-side-scroll">
<!-- Left navigation area ( Compatible layui Existing vertical navigation ) -->
<ul class="layui-nav layui-nav-tree" lay-filter="test">
<li class="layui-nav-item layui-nav-itemed">
<a class="" href="javascript:;"> System management </a>
<dl class="layui-nav-child">
<dd><a href="page/sys/user" target="mainFrame"> User list </a></dd>
<dd><a href="page/sys/role" target="mainFrame"> Character list </a></dd>
<dd><a href="page/sys/permission" target="mainFrame"> Permission list </a></dd>
</dl>
</li>
<li class="layui-nav-item">
<a href="javascript:;"> The business management </a>
<dl class="layui-nav-child">
<dd><a href="student/find" target="mainFrame"> Student list </a></dd>
<dd><a href="javascript:;"> List of employees </a></dd>
<dd><a href="javascript:;"> Department list </a></dd>
</dl>
</li>
</ul>
</div>
</div>
<div class="layui-body">
<!-- Content subject area -->
<iframe name="mainFrame" frameborder="0" style="width:100%;height: 100%" src="page/welcome"></iframe>
</div>
<div class="layui-footer">
<!-- Bottom fixed area -->
Bottom fixed area
</div>
</div>
<!-- introduce layui.js file -->
<script type="text/javascript" src="static/layui/layui.js"></script>
</body>
</html>
structure :
welcome.jsp:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<base href="${pageContext.request.contextPath}/">
<title>Title</title>
<style>
h1 {
text-align: center;
margin-top: 120px;
}
</style>
</head>
<body>
<h1> Welcome to the background management system </h1>
</body>
</html>
SystemController.java:
package com.newcapec.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
/** * The processor used to realize page Jump */
@Controller
@RequestMapping("/page")
public class SystemController {
@GetMapping("/stu/add")
public String stuAdd() {
return "stu/add";
}
@GetMapping("/welcome")
public String welcome() {
return "welcome";
}
@GetMapping("/sys/user")
public String sysUser() {
return "sys/user";
}
@GetMapping("/sys/role")
public String sysRole() {
return "sys/role";
}
@GetMapping("/sys/permission")
public String sysPermission() {
return "sys/permission";
}
@GetMapping("/emp")
public String emp() {
return "emp/find";
}
@GetMapping("/dept")
public String dept() {
return "dept/find";
}
@GetMapping("/index")
public String index() {
return "index";
}
@GetMapping("/login")
public String login() {
return "login";
}
}
3.6.2 User management page
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<base href="${pageContext.request.contextPath}/">
<title>Title</title>
<!-- introduce Layui The style file -->
<link rel="stylesheet" href="static/layui/css/layui.css">
<style>
.layui-inline {
margin-right: 15px
}
.layui-fluid {
padding-top: 15px;
}
/*layui Data table check box correction */
.layui-table-view .layui-form-checkbox i {
margin-top: 5px;
}
</style>
</head>
<body>
<div class="layui-fluid">
<!-- User list page header area : Show the search box 、 Search button 、 Add a button 、 Batch delete button -->
<blockquote class="layui-elem-quote">
<form class="layui-form" action="">
<div class="layui-inline">
<input type="text" id="username" name="username" placeholder=" user name " class="layui-input">
</div>
<div class="layui-inline">
<input type="text" id="nickname" name="nickname" placeholder=" nickname " class="layui-input">
</div>
<div class="layui-inline">
<a class="layui-btn" id="searchBtn"> Search for </a>
<a class="layui-btn layui-btn-normal" id="addBtn"> add to </a>
<a class="layui-btn layui-btn-danger" id="removeBatchBtn"> Batch deletion </a>
</div>
</form>
</blockquote>
<!-- Data table : Display data , The contents and data in the table are through js Rendered -->
<table id="dataTable" lay-filter="dataTable"></table>
<!-- Operation data template -->
<script type="text/html" id="operateBar">
<a class="layui-btn layui-btn-sm layui-btn-warm" lay-event="edit"> edit </a>
<a class="layui-btn layui-btn-sm layui-btn-danger" lay-event="remove"> Delete </a>
</script>
<!--dataWindow Page layer -->
<div id="dataWindow" style="display: none;padding: 10px">
<form id="dataForm" class="layui-form" lay-filter="dataForm">
<!--layui There are hidden fields that cannot get values bug, The following wording is recommended -->
<input type="text" name="id" style="display: none">
<div class="layui-form-item">
<label class="layui-form-label"> user name </label>
<div class="layui-input-block">
<input type="text" id="dataFormUsername" name="username" required
lay-verify="required|usernameVerify"
placeholder=" Please enter a user name "
class="layui-input">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label"> cell-phone number </label>
<div class="layui-input-block">
<input type="text" name="mobile" required lay-verify="required|phone" placeholder=" Please enter your mobile number "
class="layui-input">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label"> nickname </label>
<div class="layui-input-block">
<input type="text" name="nickname" required lay-verify="required" placeholder=" Please enter your nickname "
class="layui-input">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label"> mailbox </label>
<div class="layui-input-block">
<input type="text" name="email" required lay-verify="required|email" placeholder=" Please enter email address "
class="layui-input">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label"> Encrypting salt </label>
<div class="layui-input-block">
<input type="text" name="salt" required lay-verify="required" placeholder=" Please enter encryption salt "
class="layui-input">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label"> User state </label>
<div class="layui-input-block">
<select name="status" lay-verify="required">
<option value=""></option>
<option value="1"> normal </option>
<option value="2"> Ban </option>
</select>
</div>
</div>
<!-- The button to actually submit data , By the pop-up layer yes Callback trigger -->
<button id="submitBtn" lay-submit lay-filter="submitBtn" style="display: none"> Submit... Immediately </button>
</form>
</div>
</div>
<!-- introduce layui.js file -->
<script type="text/javascript" src="static/layui/layui.js"></script>
<script type="text/javascript">
// Load module
layui.use(['table', 'form', 'layer'], function () {
var table = layui.table,
form = layui.form,
layer = layui.layer,
$ = layui.$;
// Table data rendering
table.render({
//id: Set container unique id.id It is a necessary transfer condition for the data operation of the table .
id: 'dataTable',
elem: '#dataTable',
//height: 312,
method: 'get',
url: 'user/find', // Data interface
page: true, // Open paging
limit: '10', // Data requested per page
limits: [10, 20, 30, 40, 50],
cols: [[ // Header
{type: 'checkbox', width: 50, fixed: 'left'},
{field: 'id', title: 'ID', minWidth: 50, fixed: 'left', align: 'center'},
{field: 'username', title: ' user name ', minWidth: 100, fixed: 'left', align: 'center'},
{field: 'mobile', title: ' cell-phone number ', align: 'center'},
{field: 'nickname', title: ' nickname ', align: 'center'},
{field: 'email', title: ' mailbox ', align: 'center'},
{field: 'salt', title: ' Encrypting salt ', align: 'center'},
{
field: 'status', title: ' User state ', align: 'center', templet: function (d) {
return d.status == '1' ? ' normal ' : ' Ban ';
}
},
{title: ' operation ', minWidth: 150, fixed: 'right', align: 'center', templet: '#operateBar'},
]],
parseData: function (res) { //res That is, the original returned data
return {
"code": res.code, // Parse interface state
"msg": res.message, // Parse prompt text
"count": res.data.total, // Parse data length
"data": res.data.list // Parse data list
};
},
request: {
pageName: 'pageNum', // Parameter name of page number , Default :page
limitName: 'pageSize' // Parameter name of data volume per page , Default :limit
},
response: {
// Specify the successful status code , Default :0
statusCode: 200
}
});
// Conditions of the query
$("#searchBtn").click(function () {
tableReload();
});
$("#addBtn").click(function () {
// Add without passing id value
addOrEdit();
})
var window_index = -1; // Default form index value
function addOrEdit(id) {
// Page layer
layer.open({
type: 1,
title: id ? ' Modify the user ' : ' New users ',
content: $('#dataWindow'),
area: ['500px', '500px'], // Wide and high
btn: [' determine ', ' Cancel '],
yes: function (index) {
// If you set yes Callback , Manual closing is required
//layer.close(index);
window_index = index;
// Click the OK button , Submit form data
$("#submitBtn").click();
},
end: function () {
window_index = -1; // Reset form index defaults
// Reset form
$('#dataForm')[0].reset();
$("#dataFormUsername").prop('readonly', '');
$("#dataFormUsername").attr('lay-verify', 'required|usernameVerify');
}
});
}
// Add a form submission event
form.on('submit(submitBtn)', function (data) {
// All form fields of the current container , Name value pair form :{name: value}
console.log(data.field)
// Judge the form id Whether the field has a value , If it's worth it , Perform modification operations , Otherwise, execute new .
var url = 'user/add', method = 'post';
if (data.field.id) {
url = 'user/edit';
method = 'put';
}
//console.log(data);
$.ajax(url, {
type: method,
contentType: 'application/json',
data: JSON.stringify(data.field),
success: function (res) {
if (res.code == 200) {
// Close page layer
layer.close(window_index);
layer.msg(res.message);
tableReload();
}
}
})
return false; // Prevent form jump . If you need a form jump , Just remove this paragraph .
});
form.verify({
usernameVerify: function (value) { //value: Value of form 、item: Form DOM object
if (!new RegExp("^[a-zA-Z0-9_\u4e00-\u9fa5\\s·]+$").test(value)) {
return ' The user name cannot have special characters ';
}
if (/(^\_)|(\__)|(\_+$)/.test(value)) {
return ' The beginning and end of the user name cannot be underlined \'_\'';
}
if (/^\d+\d+\d$/.test(value)) {
return ' The user name cannot be all numbers ';
}
// Verify the uniqueness of the user name
var result = '';
$.ajax('user/findExists/' + value, {
async: false,
type: 'get',
success: function (res) {
if (res.code == 401) {
result = res.message;
}
}
})
return result;
}
});
$("#removeBatchBtn").click(function () {
// Call the function to delete data in batch
removeBatch();
});
// Toolbar events
// notes :tool Is the toolbar event name ,test yes table Properties of the original container lay-filter=" Corresponding value "
table.on('tool(dataTable)', function (obj) {
var data = obj.data; // Get current row data
var layEvent = obj.event; // get lay-event Corresponding value ( It can also be in the header event The corresponding value of the parameter )
if (layEvent === 'remove') { // Delete
remove(data.id);
} else if (layEvent === 'edit') { // edit
// The echo data
// Assign values to the form :dataForm namely class="layui-form" Attribute of the element lay-filter="" Corresponding value
form.val("dataForm", data);
/*
* When the user performs an editing operation :
* 1、 The user name is read-only
* 2、 User name does not need unique verification
* */
$("#dataFormUsername").prop('readonly', 'readonly');
$("#dataFormUsername").attr('lay-verify', '');
addOrEdit(data.id);
}
});
// A single function to delete data
function remove(id) {
layer.confirm(' Are you sure you want to delete ?', function (index) {
// Send delete instruction to the server
$.ajax('user/remove/' + id, {
type: 'delete',
success: function (res) {
if (res.code == 200) {
layer.msg(res.message);
// Reload table data
tableReload();
}
}
})
});
}
// A single function to delete data
function removeBatch() {
var checkStatus = table.checkStatus('dataTable'); //dataTable Is the basic parameter id Corresponding value
var data = checkStatus.data; // Get the data of the selected row
if (data.length == 0) {
layer.msg(" Please select the data to delete !");
} else {
layer.confirm(' Are you sure you want to delete ?', function (index) {
var ids = [];
data.forEach(function (item) {
ids.push(item.id);
})
// Send delete instruction to the server
$.ajax('user/remove?ids=' + ids.join(), {
type: 'delete',
success: function (res) {
if (res.code == 200) {
layer.msg(res.message);
// Reload table data
tableReload();
}
}
})
});
}
}
// Reload table functions
function tableReload() {
table.reload('dataTable', {
// Combined with the following search
where: {
username: $("#username").val(),
nickname: $("#nickname").val()
}
})
}
});
</script>
</body>
</html>
Four 、 System role module
4.1 Entity class
package com.newcapec.entity;
public class SysRole {
private Integer id;
private String roleCode;
private String roleName;
private String description;
private String del;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getRoleCode() {
return roleCode;
}
public void setRoleCode(String roleCode) {
this.roleCode = roleCode;
}
public String getRoleName() {
return roleName;
}
public void setRoleName(String roleName) {
this.roleName = roleName;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String getDel() {
return del;
}
public void setDel(String del) {
this.del = del;
}
}
4.2 Persistence layer
Dao Interface :
package com.newcapec.dao;
import com.newcapec.entity.SysRole;
import com.newcapec.utils.BaseDao;
public interface SysRoleDao extends BaseDao<SysRole> {
}
Mapper file :
<?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.newcapec.dao.SysRoleDao">
<insert id="insert" parameterType="com.newcapec.entity.SysRole" useGeneratedKeys="true" keyProperty="id">
insert into t_sys_role(role_code, role_name, description)
values(#{roleCode}, #{roleName}, #{description})
</insert>
<update id="update" parameterType="com.newcapec.entity.SysRole">
update t_sys_role
<set>
<if test="roleCode != null">
role_code = #{roleCode},
</if>
<if test="roleName != null">
role_name = #{roleName},
</if>
<if test="description != null">
description = #{description},
</if>
</set>
where id = #{id}
</update>
<delete id="delete" parameterType="java.lang.Integer">
update t_sys_role set del=1 where id = #{id}
</delete>
<delete id="deleteBatch" parameterType="java.lang.Integer">
update t_sys_role set del=1 where id in
<foreach collection="array" open="(" close=")" separator="," item="id">
#{id}
</foreach>
</delete>
<resultMap id="BaseResultMap" type="com.newcapec.entity.SysRole">
<id column="id" property="id"/>
<result column="role_code" property="roleCode"/>
<result column="role_name" property="roleName"/>
<result column="description" property="description"/>
</resultMap>
<select id="select" parameterType="com.newcapec.entity.SysRole" resultMap="BaseResultMap">
select id, role_code, role_name, description from t_sys_role
<where>
<if test="roleCode != null and roleCode != ''">
role_code like concat('%',#{roleCode},'%')
</if>
<if test="roleName != null and roleName != ''">
and role_name like concat('%',#{roleName},'%')
</if>
and del=0
</where>
</select>
<select id="selectById" parameterType="java.lang.Integer" resultMap="BaseResultMap">
select id, role_code, role_name, description from t_sys_role
where id = #{id} and del=0
</select>
</mapper>
4.3 The business layer
Service Interface :
package com.newcapec.service;
import com.newcapec.entity.SysRole;
import com.newcapec.utils.BaseService;
public interface SysRoleService extends BaseService<SysRole> {
}
Service Interface implementation class :
package com.newcapec.service.impl;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.newcapec.constant.CommonConstant;
import com.newcapec.dao.SysRoleDao;
import com.newcapec.entity.SysRole;
import com.newcapec.service.SysRoleService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Service
public class SysRoleServiceImpl implements SysRoleService {
@Autowired
private SysRoleDao sysRoleDao;
@Override
public void add(SysRole entity) {
sysRoleDao.insert(entity);
}
@Override
public void edit(SysRole entity) {
sysRoleDao.update(entity);
}
@Override
public void remove(Integer id) {
sysRoleDao.delete(id);
}
@Override
public void removeBatch(Integer[] ids) {
sysRoleDao.deleteBatch(ids);
}
@Override
public List<SysRole> find(SysRole entity) {
return sysRoleDao.select(entity);
}
@Override
public Map<String, Object> findPage(Integer pageNum, Integer pageSize, SysRole entity) {
// Paging service
PageHelper.startPage(pageNum, pageSize);
List<SysRole> list = sysRoleDao.select(entity);
PageInfo<SysRole> pageInfo = new PageInfo<>(list);
//1. Current page data ( Data list )2. Total records of this query
Map<String, Object> pageMap = new HashMap<>();
pageMap.put(CommonConstant.PAGE_LIST, list);
pageMap.put(CommonConstant.PAGE_TOTAL, pageInfo.getTotal());
return pageMap;
}
@Override
public SysRole findById(Integer id) {
return sysRoleDao.selectById(id);
}
}
4.4 Control layer
package com.newcapec.controller;
import com.newcapec.constant.CommonConstant;
import com.newcapec.entity.SysRole;
import com.newcapec.service.SysRoleService;
import com.newcapec.utils.Result;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/role")
public class SysRoleController {
@Autowired
private SysRoleService sysRoleService;
/** * newly added */
@PostMapping("/add")
public Result add(@RequestBody SysRole sysRole) {
sysRoleService.add(sysRole);
return Result.success();
}
/** * edit */
@PutMapping("/edit")
public Result edit(@RequestBody SysRole sysRole) {
sysRoleService.edit(sysRole);
return Result.success();
}
/** * Delete */
@DeleteMapping("/remove/{id}")
public Result remove(@PathVariable Integer id) {
sysRoleService.remove(id);
return Result.success();
}
/** * Batch deletion */
@DeleteMapping("/remove")
public Result removeBatch(Integer[] ids) {
sysRoleService.removeBatch(ids);
return Result.success();
}
/** * Single query */
@GetMapping("/find/{id}")
public Result findById(@PathVariable Integer id) {
return Result.success(sysRoleService.findById(id));
}
/** * Paging query */
@GetMapping("/findPage")
public Result findPage(@RequestParam(value = CommonConstant.PAGE_NUM, required = false, defaultValue = CommonConstant.PAGE_NUM_DEFAULT) Integer pageNum,
@RequestParam(value = CommonConstant.PAGE_SIZE, required = false, defaultValue = CommonConstant.PAGE_SIZE_DEFAULT) Integer pageSize,
SysRole sysRole) {
return Result.success(sysRoleService.findPage(pageNum, pageSize, sysRole));
}
/** * Inquire about */
@GetMapping("/find")
public Result find(SysRole sysRole) {
return Result.success(sysRoleService.find(sysRole));
}
}
4.5 Foreground page
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<base href="${pageContext.request.contextPath}/">
<title>Title</title>
<link rel="stylesheet" href="static/layui/css/layui.css">
<style>
/*layui Data table check box correction */
.layui-table-view .layui-form-checkbox i {
margin-top: 5px;
}
</style>
</head>
<body>
<div style="padding: 10px">
<blockquote class="layui-elem-quote">
<form class="layui-form">
<div class="layui-inline">
<input type="text" id="roleCode" name="roleCode" placeholder=" Character encoding " class="layui-input">
</div>
<div class="layui-inline">
<input type="text" id="roleName" name="roleName" placeholder=" Character name " class="layui-input">
</div>
<div class="layui-inline">
<a class="layui-btn searchBtn"> Search for </a>
<a class="layui-btn layui-btn-normal addBtn"> add to </a>
<a class="layui-btn layui-btn-danger removeBtn"> Batch deletion </a>
</div>
</form>
</blockquote>
<table id="tab" lay-filter="tab"></table>
<!-- Operations in the table -->
<script type="text/html" id="roleBar">
<a class="layui-btn layui-btn-xs layui-btn-warm" lay-event="edit"> edit </a>
<a class="layui-btn layui-btn-xs layui-btn-danger" lay-event="remove"> Delete </a>
</script>
<!-- Forms -->
<div id="dataWindow" style="display: none;padding: 10px;">
<form id="dataForm" class="layui-form" lay-filter="dataForm">
<input type="text" name="id" style="display: none;">
<div class="layui-form-item">
<label class="layui-form-label"> Character encoding </label>
<div class="layui-input-block">
<input type="text" name="roleCode" lay-verify="required" placeholder=" Please enter the character code " class="layui-input">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label"> Character name </label>
<div class="layui-input-block">
<input type="text" name="roleName" lay-verify="required" placeholder=" Please enter the role name " class="layui-input">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label"> describe </label>
<div class="layui-input-block">
<input type="text" name="description" lay-verify="required" placeholder=" Please enter a description " class="layui-input">
</div>
</div>
<%--<div class="layui-form-item">
<label class="layui-form-label"> jurisdiction </label>
<div class="layui-input-block">
<div id="permissionTree"></div>
</div>
</div>--%>
<button class="submitBtn" lay-submit lay-filter="submitBtn" style="display: none;"> Submit... Immediately </button>
</form>
</div>
</div>
<script type="text/javascript" src="static/layui/layui.js"></script>
<script type="text/javascript">
layui.use(['table', 'form', 'layer', 'tree'], function () {
var form = layui.form,
layer = layui.layer,
table = layui.table,
tree = layui.tree,
$ = layui.$;
// Asynchronous table initialization
table.render({
id: 'roleTable',
elem: '#tab',
// Asynchronous requests
method: 'get',
url: 'role/findPage',
// Pagination
page: true,
limit: 10,
limits: [10, 20, 30, 50],
// Set the header
cols: [[
{type: 'checkbox', width: 50, fixed: 'left'},
{field: 'id', title: 'ID', minWidth: 50, fixed: 'left', align: 'center'},
{field: 'roleCode', title: ' Character encoding ', minWidth: 100, fixed: 'left', align: 'center'},
{field: 'roleName', title: ' Character name ', align: 'center'},
{field: 'description', title: ' describe ', align: 'center'},
{title: ' operation ', minWidth: 150, fixed: 'right', align: 'center', templet: '#roleBar'}
]],
//res It is the data of the background response
parseData: function (res) {
return {
// Parse interface state
'code': res.code,
// Parse prompt text
'msg': res.message,
// Parse data length
'count': res.data.total,
// Parse data list
'data': res.data.list
};
},
request: {
// Parameter name of page number , Default :page
pageName: 'pageNum',
// Parameter name of data volume per page , Default :limit
limitName: 'pageSize'
},
response: {
// Specify the successful status code , Default :0
statusCode: 200
}
});
// Conditions of the query
$('.searchBtn').click(function () {
tableReload();
});
// Line tool Events
// notes :tool Is the toolbar event name ,test yes table Properties of the original container lay-filter=" Corresponding value "
table.on('tool(tab)', function (obj) {
// Get current row data
var data = obj.data;
// get lay-event Corresponding value ( It can also be in the header event The corresponding value of the parameter )
var layEvent = obj.event;
if (layEvent == 'edit') {
// The echo data
form.val("dataForm", data);
// Click the edit button
addOrEdit(data.id);
} else if (layEvent == 'remove') {
// Click the delete button
remove(data.id);
}
});
// Single delete function
function remove(id) {
layer.confirm(' Are you sure you want to delete ?', function () {
// Delete by asynchronous request
$.ajax('role/remove/' + id, {
type: 'delete',
success: function (res) {
if (res.code == 200) {
layer.msg(res.message);
// Table overload
tableReload();
}
}
});
});
}
// Batch delete function
function removeBatch() {
// Get the selected data status of the table
var checkStatus = table.checkStatus('roleTable');
// Get selected data
var checkData = checkStatus.data;
if (checkData.length == 0) {
layer.msg(' Please select the data to delete ');
} else {
layer.confirm(' Are you sure you want to delete ?', function () {
var array = [];
checkData.forEach(function (item) {
array.push(item.id);
});
$.ajax('role/remove?ids=' + array.join(), {
type: 'delete',
success: function (res) {
if (res.code == 200) {
layer.msg(res.message);
// Table overload
tableReload();
}
}
});
});
}
}
$('.removeBtn').click(function () {
removeBatch();
})
// newly added
var window_index = -1;
function addOrEdit(id) {
layer.open({
type: 1,
title: id ? ' Role editor ' : ' Role addition ',
content: $('#dataWindow'),
btn: [' determine ', ' Cancel '],
// Click the OK button to the event
yes: function (index) {
window_index = index
$('.submitBtn').click();
},
// Click the pop-up layer to hide the event
end: function () {
window_index = -1;
// Empty the form
$('#dataForm')[0].reset();
}
});
}
$('.addBtn').click(function () {
addOrEdit();
});
// Form submission time
form.on('submit(submitBtn)', function (data) {
// All form fields of the current container , Name value pair form :{name: value}
var url = 'role/add';
var method = 'post';
if (data.field.id) {
//id Parameter data indicates that the current operation is edit , Otherwise, it is new
url = 'role/edit';
method = 'put';
}
$.ajax(url, {
type: method,
contentType: 'application/json',
data: JSON.stringify(data.field),
success: function (res) {
if (res.code = 200) {
layer.close(window_index);
layer.msg(res.message);
tableReload();
}
}
});
// Prevent form jump . If you need a form jump , Just remove this paragraph .
return false;
});
// Table overload
function tableReload() {
table.reload('roleTable', {
where: {
roleCode: $('#roleCode').val(),
roleName: $('#roleName').val()
}
});
}
});
</script>
</body>
</html>
5、 ... and 、 System authority module
5.1 Entity class
package com.newcapec.entity;
public class SysPermission {
private Integer id;
private String name;
private String type;
private String url;
private String percode;
private Integer parentId;
private Integer sort;
private String del;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getPercode() {
return percode;
}
public void setPercode(String percode) {
this.percode = percode;
}
public Integer getParentId() {
return parentId;
}
public void setParentId(Integer parentId) {
this.parentId = parentId;
}
public Integer getSort() {
return sort;
}
public void setSort(Integer sort) {
this.sort = sort;
}
public String getDel() {
return del;
}
public void setDel(String del) {
this.del = del;
}
}
5.2 Persistence layer
Dao Interface :
package com.newcapec.dao;
import com.newcapec.entity.SysPermission;
import com.newcapec.utils.BaseDao;
public interface SysPermissionDao extends BaseDao<SysPermission> {
}
Mapper file :
<?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.newcapec.dao.SysPermissionDao">
<insert id="insert" parameterType="com.newcapec.entity.SysPermission" useGeneratedKeys="true" keyProperty="id">
insert into t_sys_permission(name, type, url, percode, parent_id, sort)
values(#{name}, #{type}, #{url}, #{percode}, #{parentId}, #{sort})
</insert>
<update id="update" parameterType="com.newcapec.entity.SysPermission">
update t_sys_permission
<set>
<if test="name != null">
name = #{name},
</if>
<if test="type != null">
type = #{type},
</if>
<if test="url != null">
url = #{url},
</if>
<if test="percode != null">
percode = #{percode},
</if>
<if test="parentId != null">
parent_id = #{parentId},
</if>
<if test="sort != null">
sort = #{sort},
</if>
</set>
where id = #{id}
</update>
<delete id="delete" parameterType="java.lang.Integer">
update t_sys_permission set del=1 where id = #{id}
</delete>
<delete id="deleteBatch" parameterType="java.lang.Integer">
update t_sys_permission set del=1 where id in
<foreach collection="array" open="(" close=")" separator="," item="id">
#{id}
</foreach>
</delete>
<resultMap id="BaseResultMap" type="com.newcapec.entity.SysPermission">
<id column="id" property="id"/>
<result column="name" property="name"/>
<result column="type" property="type"/>
<result column="url" property="url"/>
<result column="percode" property="percode"/>
<result column="parent_id" property="parentId"/>
<result column="sort" property="sort"/>
</resultMap>
<select id="select" parameterType="com.newcapec.entity.SysPermission" resultMap="BaseResultMap">
select id, name, type, url, percode, parent_id, sort from t_sys_permission
<where>
<if test="name != null and name != ''">
name like concat('%',#{name},'%')
</if>
<if test="type != null and type != ''">
and type = #{type}
</if>
and del=0
</where>
</select>
<select id="selectById" parameterType="java.lang.Integer" resultMap="BaseResultMap">
select id, name, type, url, percode, parent_id, sort from t_sys_permission
where id = #{id} and del=0
</select>
</mapper>
5.3 The business layer
Service Interface :
package com.newcapec.service;
import com.newcapec.entity.SysPermission;
import com.newcapec.utils.BaseService;
public interface SysPermissionService extends BaseService<SysPermission> {
}
Service Interface implementation class :
package com.newcapec.service.impl;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.newcapec.constant.CommonConstant;
import com.newcapec.dao.SysPermissionDao;
import com.newcapec.entity.SysPermission;
import com.newcapec.service.SysPermissionService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Service
public class SysPermissionServiceImpl implements SysPermissionService {
@Autowired
private SysPermissionDao sysPermissionDao;
@Override
public void add(SysPermission entity) {
sysPermissionDao.insert(entity);
}
@Override
public void edit(SysPermission entity) {
sysPermissionDao.update(entity);
}
@Override
public void remove(Integer id) {
sysPermissionDao.delete(id);
}
@Override
public void removeBatch(Integer[] ids) {
sysPermissionDao.deleteBatch(ids);
}
@Override
public List<SysPermission> find(SysPermission entity) {
return sysPermissionDao.select(entity);
}
@Override
public Map<String, Object> findPage(Integer pageNum, Integer pageSize, SysPermission entity) {
// Paging service
PageHelper.startPage(pageNum, pageSize);
List<SysPermission> list = sysPermissionDao.select(entity);
PageInfo<SysPermission> pageInfo = new PageInfo<>(list);
//1. Current page data ( Data list )2. Total records of this query
Map<String, Object> pageMap = new HashMap<>();
pageMap.put(CommonConstant.PAGE_LIST, list);
pageMap.put(CommonConstant.PAGE_TOTAL, pageInfo.getTotal());
return pageMap;
}
@Override
public SysPermission findById(Integer id) {
return sysPermissionDao.selectById(id);
}
}
5.4 Control layer
package com.newcapec.controller;
import com.newcapec.constant.CommonConstant;
import com.newcapec.entity.SysPermission;
import com.newcapec.service.SysPermissionService;
import com.newcapec.utils.Result;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/permission")
public class SysPermissionController {
@Autowired
private SysPermissionService sysPermissionService;
/** * newly added */
@PostMapping("/add")
public Result add(@RequestBody SysPermission sysPermission) {
sysPermissionService.add(sysPermission);
return Result.success();
}
/** * edit */
@PutMapping("/edit")
public Result edit(@RequestBody SysPermission sysPermission) {
sysPermissionService.edit(sysPermission);
return Result.success();
}
/** * Delete */
@DeleteMapping("/remove/{id}")
public Result remove(@PathVariable Integer id) {
sysPermissionService.remove(id);
return Result.success();
}
/** * Batch deletion */
@DeleteMapping("/remove")
public Result removeBatch(Integer[] ids) {
sysPermissionService.removeBatch(ids);
return Result.success();
}
/** * Single query */
@GetMapping("/find/{id}")
public Result findById(@PathVariable Integer id) {
return Result.success(sysPermissionService.findById(id));
}
/** * Paging query */
@GetMapping("/findPage")
public Result findPage(@RequestParam(value = CommonConstant.PAGE_NUM, required = false, defaultValue = CommonConstant.PAGE_NUM_DEFAULT) Integer pageNum,
@RequestParam(value = CommonConstant.PAGE_SIZE, required = false, defaultValue = CommonConstant.PAGE_SIZE_DEFAULT) Integer pageSize,
SysPermission sysPermission) {
return Result.success(sysPermissionService.findPage(pageNum, pageSize, sysPermission));
}
/** * Inquire about */
@GetMapping("/find")
public Result find(SysPermission sysPermission) {
return Result.success(sysPermissionService.find(sysPermission));
}
}
5.5 Foreground page
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<base href="${pageContext.request.contextPath}/">
<title>Title</title>
<link rel="stylesheet" href="static/layui/css/layui.css">
<style>
/*layui Data table check box correction */
.layui-table-view .layui-form-checkbox i {
margin-top: 5px;
}
</style>
</head>
<body>
<div style="padding: 10px">
<blockquote class="layui-elem-quote">
<form class="layui-form">
<div class="layui-inline">
<input type="text" id="name" name="name" placeholder=" Permission to name " class="layui-input">
</div>
<div class="layui-inline">
<select id="type" name="type">
<option value=""> Authority type </option>
<option value="1"> Catalog </option>
<option value="2"> menu </option>
<option value="3"> Button </option>
</select>
</div>
<div class="layui-inline">
<a class="layui-btn searchBtn"> Search for </a>
<a class="layui-btn layui-btn-normal addBtn"> add to </a>
<a class="layui-btn layui-btn-danger removeBtn"> Batch deletion </a>
</div>
</form>
</blockquote>
<table id="tab" lay-filter="tab"></table>
<!-- Operations in the table -->
<script type="text/html" id="permissionBar">
<a class="layui-btn layui-btn-xs layui-btn-warm" lay-event="edit"> edit </a>
<a class="layui-btn layui-btn-xs layui-btn-danger" lay-event="remove"> Delete </a>
</script>
<!-- Forms -->
<div id="dataWindow" style="display: none;padding: 10px;">
<form id="dataForm" class="layui-form" lay-filter="dataForm">
<input type="text" name="id" style="display: none;">
<div class="layui-form-item">
<label class="layui-form-label"> Permission to name </label>
<div class="layui-input-block">
<input type="text" name="name" lay-verify="required" placeholder=" Please enter the permission name " class="layui-input">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label"> Authority type </label>
<div class="layui-input-block">
<select name="type" lay-verify="required">
<option value=""> Please select </option>
<option value="1"> Catalog </option>
<option value="2"> menu </option>
<option value="3"> Button </option>
</select>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label"> Access address </label>
<div class="layui-input-block">
<input type="text" name="url" placeholder=" Please enter the access address " class="layui-input">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label"> Authority code </label>
<div class="layui-input-block">
<input type="text" name="percode" placeholder=" Please enter the permission code " class="layui-input">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label"> Parent node </label>
<div class="layui-input-block">
<input type="text" name="parentId" placeholder=" Please enter the parent node " class="layui-input"/>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label"> According to the order </label>
<div class="layui-input-block">
<input type="text" name="sort" placeholder=" Please enter the display order " class="layui-input">
</div>
</div>
<button class="submitBtn" lay-submit lay-filter="submitBtn" style="display: none;"> Submit... Immediately </button>
</form>
</div>
</div>
<script type="text/javascript" src="static/layui/layui.js"></script>
<script type="text/javascript">
layui.use(['table', 'form', 'layer'], function () {
var form = layui.form,
layer = layui.layer,
table = layui.table,
dropdown = layui.dropdown,
tree = layui.tree,
$ = layui.$;
// Asynchronous table initialization
table.render({
id: 'permissionTable',
elem: '#tab',
// Asynchronous requests
method: 'get',
url: 'permission/findPage',
// Pagination
page: true,
limit: 10,
limits: [10, 20, 30, 50],
// Set the header
cols: [[
{type: 'checkbox', width: 50, fixed: 'left'},
{field: 'id', title: 'ID', minWidth: 50, fixed: 'left', align: 'center'},
{field: 'name', title: ' Permission to name ', minWidth: 100, fixed: 'left', align: 'center'},
{
field: 'type', title: ' Authority type ', align: 'center', templet: function (d) {
var result = ''
switch (d.type) {
case '1':
result = ' Catalog ';
break;
case '2':
result = ' menu ';
break;
case '3':
result = ' Button ';
break;
}
return result;
}
},
{field: 'url', title: ' Access address ', align: 'center'},
{field: 'percode', title: ' Authority code ', align: 'center'},
{field: 'parentId', title: ' Parent node ', align: 'center'},
{field: 'sort', title: ' According to the order ', align: 'center'},
{title: ' operation ', minWidth: 150, fixed: 'right', align: 'center', templet: '#permissionBar'}
]],
//res It is the data of the background response
parseData: function (res) {
return {
// Parse interface state
'code': res.code,
// Parse prompt text
'msg': res.message,
// Parse data length
'count': res.data.total,
// Parse data list
'data': res.data.list
};
},
request: {
// Parameter name of page number , Default :page
pageName: 'pageNum',
// Parameter name of data volume per page , Default :limit
limitName: 'pageSize'
},
response: {
// Specify the successful status code , Default :0
statusCode: 200
}
});
// Conditions of the query
$('.searchBtn').click(function () {
tableReload();
});
// Line tool Events
// notes :tool Is the toolbar event name ,test yes table Properties of the original container lay-filter=" Corresponding value "
table.on('tool(tab)', function (obj) {
// Get current row data
var data = obj.data;
// get lay-event Corresponding value ( It can also be in the header event The corresponding value of the parameter )
var layEvent = obj.event;
if (layEvent == 'edit') {
// The echo data
form.val("dataForm", data);
// Click the edit button
addOrEdit(data.id);
} else if (layEvent == 'remove') {
// Click the delete button
remove(data.id);
}
});
// Single delete function
function remove(id) {
layer.confirm(' Are you sure you want to delete ?', function () {
// Delete by asynchronous request
$.ajax('permission/remove/' + id, {
type: 'delete',
success: function (res) {
if (res.code == 200) {
layer.msg(res.message);
// Table overload
tableReload();
}
}
});
});
}
// Batch delete function
function removeBatch() {
// Get the selected data status of the table
var checkStatus = table.checkStatus('permissionTable');
// Get selected data
var checkData = checkStatus.data;
if (checkData.length == 0) {
layer.msg(' Please select the data to delete ');
} else {
layer.confirm(' Are you sure you want to delete ?', function () {
var array = [];
checkData.forEach(function (item) {
array.push(item.id);
});
$.ajax('permission/remove?ids=' + array.join(), {
type: 'delete',
success: function (res) {
if (res.code == 200) {
layer.msg(res.message);
// Table overload
tableReload();
}
}
});
});
}
}
$('.removeBtn').click(function () {
removeBatch();
})
// newly added
var window_index = -1;
function addOrEdit(id) {
layer.open({
type: 1,
title: id ? ' Permission edit ' : ' New permission ',
content: $('#dataWindow'),
btn: [' determine ', ' Cancel '],
// Click the OK button to the event
yes: function (index) {
window_index = index
$('.submitBtn').click();
},
// Click the pop-up layer to hide the event
end: function () {
window_index = -1;
// Empty the form
$('#dataForm')[0].reset();
}
});
}
$('.addBtn').click(function () {
addOrEdit();
});
// Form submission time
form.on('submit(submitBtn)', function (data) {
// All form fields of the current container , Name value pair form :{name: value}
var url = 'permission/add';
var method = 'post';
if (data.field.id) {
//id Parameter data indicates that the current operation is edit , Otherwise, it is new
url = 'permission/edit';
method = 'put';
}
$.ajax(url, {
type: method,
contentType: 'application/json',
data: JSON.stringify(data.field),
success: function (res) {
if (res.code = 200) {
layer.close(window_index);
layer.msg(res.message);
tableReload();
}
}
});
// Prevent form jump . If you need a form jump , Just remove this paragraph .
return false;
});
// Table overload
function tableReload() {
table.reload('permissionTable', {
where: {
name: $('#name').val(),
type: $('#type').val()
}
});
}
});
</script>
</body>
</html>
SSM Integrate _ Rights management
One 、 Authority management system analysis
1.1 summary
Rights management , Generally, it refers to the security rules or security policies set by the system , Users can access and only access their authorized resources , No less . Authority management appears in almost any system , As long as there's a system with users and passwords . Many people often “ User authentication ”、“ Password encryption ”、“ System management ” And other concepts are confused with the concept of permission management .
User authentication , It doesn't belong to authority management at all . User authentication , Is to solve such a problem : The user tells the system “ Who am I ”, The system asks the user how to prove that you are “ who ” Well ? For using user name 、 Password verification system , Then show me your password . When the user name and password match , Then it proves who the current user is ; For systems like fingerprints , Show me your fingerprints ; For hardware Key Wait for the card system , You need to swipe your card .
Password encryption , It belongs to the field of user identity authentication , It does not belong to the scope of authority management .
System management , It is generally a module of the system . Moreover, the module generally also contains authority management sub module . therefore , Many people mistakenly think that the authority management system is just a small sub module of the system . Authority management module in system management , Just an operation interface , Let enterprises IT Administrators can set security policies such as roles . There are many permission verification logic behind the system , None of these belong to this module . On the whole , This module is equivalent to providing some data to the authority management module .
At present, it is mainly through users 、 role 、 Resources are used to allocate permissions . say concretely , Is to give users a role , Roles can access and operate resources in different ranges . By establishing a role system , Separate users and resources , To ensure the implementation of permission allocation .
Generally, it refers to the security rules or security policies set by the system , Users can access and only access their authorized resources .
1.2 Examples of scenes
Enterprises IT Administrators can generally define roles for the system , Assign roles to users . This is the most common role-based access control . Examples of scenes :
1、 Give Zhang San “ HR Manager ” role ,“ HR Manager ” have “ Query employees ”、“ Add employees ”、“ Modify employees ” and “ Delete employee ” jurisdiction . At this time, Zhang San can enter the system , You can do these operations .
2、 Remove Li Si's “ HR Manager ” role , At this time, Li Si cannot enter the system for these operations .
For example , Limited to function access . There are some more abundant 、 More detailed permission management . such as :
1、 Because Zhang San is from Beijing Branch “ HR Manager ”, So he can and can only manage the employees of Beijing Branch and the subsidiaries of Beijing Branch ( Haidian subsidiary 、 Chaoyang subsidiary 、 Xicheng subsidiary 、 Dongcheng subsidiary, etc ) The employees' .
2、 Because Wang Wu is a subsidiary of Haidian “ HR Manager ”, So he can and can only manage the employees of Haidian subsidiary .
3、 The authority of the general examiner to review financial data is : The maximum audit limit in the retail industry is ¥50 ten thousand , The maximum limit in the steel industry is ¥1000 ten thousand ; The senior examiner is not subject to this limit .
4、ATM Withdrawal the amount of each withdrawal cannot exceed ¥5000 element , The total withdrawal amount per day cannot exceed ¥20000 element .
These rights management and data ( It can be collectively referred to as resources ) Direct correlation , Also known as data level permission management 、 Fine grained permission management or content permission management .
1.3 classification
From the point of view of control , Permission management can be divided into two categories :
- Function level authority management ;
- Data level privilege management .
In terms of control direction , You can also divide permission management into two categories :
- Get data from the system , For example, to inquire about an order 、 Search for customer information ;
- Submit data to the system , For example, to delete an order 、 Modify customer profile .
Two 、 Authority management cases
2.1 Permission involves 5 A watch
User table , Role table , Permissions on the table , User role relationship table , Role permission association table .
When the user logs in , Verify whether the information in the user table is legal according to the user name and password , If it is legal, get user information , Then according to the user's id Go to the user role relationship table to get the associated roles id aggregate , Then according to the role id Then go to the role permission relationship table to obtain the permissions owned by the role id aggregate , Then basic permissions id Set to the permission table to get the specific menu , Show it to the current login user , Thus, no user can see the unused menu permission .
Table function introduction
- User table : Record the basic information of users .
-- ----------------------------
-- User table
-- ----------------------------
DROP TABLE IF EXISTS `t_sys_user`;
CREATE TABLE `t_sys_user` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT ' Primary key ',
`username` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT ' Login account ',
`mobile` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT ' Phone number ',
`nickname` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT ' The user nickname ',
`email` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT ' User mailbox ',
`userpwd` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT ' password ',
`salt` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT 'newedu' COMMENT ' Encrypting salt ',
`status` char(1) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '1' COMMENT ' state :1 You can use 2 Unavailable ',
`del` char(1) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '0' COMMENT ' Whether or not to delete :0 normal 1 Delete ',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = ' User information sheet ' ROW_FORMAT = Dynamic;
-- ----------------------------
-- User table data
-- ----------------------------
INSERT INTO `t_sys_user` VALUES (1, 'admin', '13612345678', ' Administrators ', '[email protected]', '8f32e9f68d6886d095b230b93e7a2c86', 'newedu', '1', '0');
INSERT INTO `t_sys_user` VALUES (2, 'tom', '12345678901', ' Tom ', '[email protected]', '8f32e9f68d6886d095b230b93e7a2c86', 'newedu', '1', '0');
- Role table : Record the basic information of the role .
-- ----------------------------
-- Role table
-- ----------------------------
DROP TABLE IF EXISTS `t_sys_role`;
CREATE TABLE `t_sys_role` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'id',
`role_code` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT ' Character encoding ',
`role_name` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT ' Character name ',
`description` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT ' describe ',
`del` char(1) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '0' COMMENT ' Whether or not to delete :0 normal 1 Delete ',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = ' Role information sheet ' ROW_FORMAT = Dynamic;
-- ----------------------------
-- Role table data
-- ----------------------------
INSERT INTO `t_sys_role` VALUES (1, 'admin', ' Administrators ', ' Administrators ', '0');
INSERT INTO `t_sys_role` VALUES (2, 'user', ' Ordinary users ', ' Ordinary users ', '0');
INSERT INTO `t_sys_role` VALUES (3, 'other', ' other ', ' other ', '0');
- Permissions on the table : Record basic information about permissions .
-- ----------------------------
-- Permissions on the table
-- ----------------------------
DROP TABLE IF EXISTS `t_sys_permission`;
CREATE TABLE `t_sys_permission` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'id',
`name` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT ' Permission to name ',
`type` char(1) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT ' Authority type :1 Catalog 2 menu 3 Button ',
`url` varchar(200) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '#' COMMENT ' Access address ',
`percode` varchar(200) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT ' Authority code ',
`parent_id` int(11) NULL DEFAULT 0 COMMENT ' Parent node ID',
`sort` int(11) NULL DEFAULT NULL COMMENT ' According to the order ',
`del` char(1) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '0' COMMENT ' Whether or not to delete :0 normal 1 Delete ',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 14 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = ' Permission information table ' ROW_FORMAT = Dynamic;
-- ----------------------------
-- Permission table data
-- ----------------------------
INSERT INTO `t_sys_permission` VALUES (1, ' System management ', '1', '', 'system', 0, 1, '0');
INSERT INTO `t_sys_permission` VALUES (2, ' User list ', '2', '', 'user', 1, 11, '0');
INSERT INTO `t_sys_permission` VALUES (3, ' User query ', '3', '', 'user:query', 2, 111, '0');
INSERT INTO `t_sys_permission` VALUES (4, ' New users ', '3', '', 'user:add', 2, 112, '0');
INSERT INTO `t_sys_permission` VALUES (5, ' User edit ', '3', '', 'user:edit', 2, 113, '0');
INSERT INTO `t_sys_permission` VALUES (6, ' User deletion ', '3', '', 'user:remove', 2, 114, '0');
INSERT INTO `t_sys_permission` VALUES (7, ' Character list ', '2', '', 'role', 1, 12, '0');
INSERT INTO `t_sys_permission` VALUES (8, ' Role search ', '3', '', 'role:query', 7, 121, '0');
INSERT INTO `t_sys_permission` VALUES (9, ' Role addition ', '3', '', 'role:add', 7, 122, '0');
INSERT INTO `t_sys_permission` VALUES (10, ' Role editor ', '3', '', 'role:edit', 7, 123, '0');
INSERT INTO `t_sys_permission` VALUES (11, ' Character delete ', '3', '', 'role:remove', 7, 124, '0');
INSERT INTO `t_sys_permission` VALUES (12, ' Permission list ', '2', '', 'permission', 1, 13, '0');
INSERT INTO `t_sys_permission` VALUES (13, ' Permission query ', '3', '', 'permission:query', 12, 131, '0');
INSERT INTO `t_sys_permission` VALUES (14, ' New permission ', '3', '', 'permission:add', 12, 132, '0');
INSERT INTO `t_sys_permission` VALUES (15, ' Permission edit ', '3', '', 'permission:edit', 12, 133, '0');
INSERT INTO `t_sys_permission` VALUES (16, ' Permission deletion ', '3', '', 'permission:remove', 12, 134, '0');
- User role middle table : Record the roles owned by users .
- A user can have multiple roles , One-to-many relation .
- A role can be included in multiple users , One-to-many relation .
- If two tables have a two-way one to many relationship , So they have a many to many relationship , And there must be a relationship description table as an intermediate table .
-- ----------------------------
-- User role middle table
-- ----------------------------
DROP TABLE IF EXISTS `t_sys_user_role`;
CREATE TABLE `t_sys_user_role` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT ' Primary key ',
`user_id` int(11) NOT NULL COMMENT ' user ID',
`role_id` int(11) NOT NULL COMMENT ' role ID',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 4 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = ' User and role association table ' ROW_FORMAT = Dynamic;
-- ----------------------------
-- User role middle table data
-- ----------------------------
INSERT INTO `t_sys_user_role` VALUES (1, 1, 1);
INSERT INTO `t_sys_user_role` VALUES (2, 1, 2);
INSERT INTO `t_sys_user_role` VALUES (3, 2, 2);
- Role authority middle table : Record the permissions of the role .
- A role can have multiple permissions , One-to-many relation .
- A permission can be contained in multiple roles , One-to-many relation .
-- ----------------------------
-- Role authority middle table
-- ----------------------------
DROP TABLE IF EXISTS `t_sys_role_permission`;
CREATE TABLE `t_sys_role_permission` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT ' Primary key ',
`role_id` int(11) NOT NULL COMMENT ' role ID',
`permission_id` int(11) NOT NULL COMMENT ' jurisdiction ID',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 18 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = ' Role and permission association table ' ROW_FORMAT = Dynamic;
-- ----------------------------
-- Role permission intermediate table data
-- ----------------------------
INSERT INTO `t_sys_role_permission` VALUES (1, 1, 1);
INSERT INTO `t_sys_role_permission` VALUES (2, 1, 2);
INSERT INTO `t_sys_role_permission` VALUES (3, 1, 3);
INSERT INTO `t_sys_role_permission` VALUES (4, 1, 4);
INSERT INTO `t_sys_role_permission` VALUES (5, 1, 5);
INSERT INTO `t_sys_role_permission` VALUES (6, 1, 6);
INSERT INTO `t_sys_role_permission` VALUES (7, 1, 7);
INSERT INTO `t_sys_role_permission` VALUES (8, 1, 8);
INSERT INTO `t_sys_role_permission` VALUES (9, 1, 9);
INSERT INTO `t_sys_role_permission` VALUES (10, 1, 10);
INSERT INTO `t_sys_role_permission` VALUES (11, 1, 11);
INSERT INTO `t_sys_role_permission` VALUES (12, 1, 12);
INSERT INTO `t_sys_role_permission` VALUES (13, 1, 13);
INSERT INTO `t_sys_role_permission` VALUES (14, 2, 1);
INSERT INTO `t_sys_role_permission` VALUES (15, 2, 2);
INSERT INTO `t_sys_role_permission` VALUES (16, 2, 6);
INSERT INTO `t_sys_role_permission` VALUES (17, 2, 10);
2.2 Display of parent node name in permission data
Display the modified name of the parent node of the permission table , The name of the parent authority that can display the current authority data .
Realize the idea :
1、 In the permission entity , Add an associated attribute , Attribute types SysPermission, And provide getter and setter Method .
notes : Show only the name of the parent permission , Definition String The type is OK .
2、 modify SysPermissionMapper.xml Query for SQL, And pass resultMap mapping .
3、 modify role.jsp Display contents of page data table .
SysPermission.java:
package com.newcapec.entity;
public class SysPermission {
// Other slightly
/* * Association attribute */
private SysPermission parent;
public SysPermission getParent() {
return parent;
}
public void setParent(SysPermission parent) {
this.parent = parent;
}
}
SysPermissionMapper.xml:
<resultMap id="selectResultMap" type="com.newcapec.entity.SysPermission" extends="BaseResultMap">
<association property="parent" javaType="com.newcapec.entity.SysPermission">
<id property="id" column="parent_id"/>
<result property="name" column="parent_name"/>
</association>
</resultMap>
<select id="select" parameterType="com.newcapec.entity.SysPermission" resultMap="selectResultMap">
select a.id, a.name, a.type, a.url, a.percode, a.parent_id, a.sort, b.name parent_name from t_sys_permission a
left join t_sys_permission b on a.parent_id = b.id
<where>
<if test="name != null and name != ''">
a.name like concat('%',#{name},'%')
</if>
<if test="type != null and type != ''">
and a.type = #{type}
</if>
and a.del=0
</where>
</select>
permission.jsp:
{
field: 'parent', title: ' Parent node ', align: 'center', templet:function (d){
return d.parent.name ? d.parent.name : ' nothing '
}},
2.3 When adding and editing permission data, query the parent node in association
In addition , Edit page add or modify parent node .
Realize the idea :
1、 modify permission.jsp page , Add and edit the control type of the parent node in the form , Change from input box to drop-down box .
2、 When adding and modifying , Load all existing nodes , These nodes are the parent nodes by default , Dynamically loaded into the drop-down box .
3、 Modify the operating , After dynamically loading all parent nodes , Then render the form .
permission.jsp:
<div class="layui-form-item">
<label class="layui-form-label"> Parent node </label>
<div class="layui-input-block">
<select id="parentId" name="parentId"></select>
</div>
</div>
<script type="text/javascript">
layui.use(['table', 'form', 'layer'], function () {
// Other slightly
// Line tool Events
// notes :tool Is the toolbar event name ,test yes table Properties of the original container lay-filter=" Corresponding value "
table.on('tool(tab)', function (obj) {
// Get current row data
var data = obj.data;
// get lay-event Corresponding value ( It can also be in the header event The corresponding value of the parameter )
var layEvent = obj.event;
if (layEvent == 'edit') {
// When you click the Modify button , No more immediate data echo . But after loading dynamic data , Display the data
//form.val("dataForm", data);
// Click the edit button
addOrEdit(data.id);
} else if (layEvent == 'remove') {
// Click the delete button
remove(data.id);
}
});
// Add or modify
var window_index = -1;
function addOrEdit(id) {
layer.open({
type: 1,
title: id ? ' Permission edit ' : ' New permission ',
content: $('#dataWindow'),
btn: [' determine ', ' Cancel '],
// Click the OK button to the event
yes: function (index) {
window_index = index
$('.submitBtn').click();
},
// Click the pop-up layer to display the subsequent events
success: function(){
// After the new and edit forms are opened , Load the dynamic form data in the form
loadParent(function(){
if(id){
$.ajax('permission/find/'+id, {
type: 'get',
success: function(res){
if(res.code == 200){
form.val('dataForm', res.data);
}
}
});
}
});
},
// Click the pop-up layer to hide the event
end: function () {
window_index = -1;
// Empty the form
$('#dataForm')[0].reset();
}
});
}
// Load parent node data ,follow Is the callback function
function loadParent(follow){
$.ajax('permission/find', {
type: 'get',
success: function(res){
var str = '<option value="0"> Please select </option>';
res.data.forEach(function(item){
str += '<option value="' + item.id + '">' + (item.parent.name?item.parent.name:' nothing ') + ':' + item.name + '</option>'
});
$('#parentId').html(str);
// to update dataForm In the form select Component rendering
form.render('select', 'dataForm');
// How to ensure the execution order of multiple asynchronous requests : Only after the first asynchronous execution is completed can the second asynchronous execution be executed
/**
* 1. Synchronization request
* $.ajax(url1, {
* async: false
* })
* $.ajax(url2, {
* async: false
* })
* Subsequent code
*
* 2. Asynchronous request nesting : Call the second asynchronous request in the callback function of the first asynchronous request
* $.ajax(url1, {
* success: function(){
* $.ajax(url2)
* }
* })
*
* 3.Promise
*/
follow();
}
});
}
});
</script>
2.4 Associate roles when users add and edit
2.4.1 Background implementation
When users add and edit , Roles related to the associated operation user . A user can assign multiple roles .
Realize the idea :
1、 stay SysUser Add associated attributes to entity classes , The attribute type is List<Integer> roleIdList, Record the list of role numbers related to the current user , And provide the corresponding getter and setter Method .
2、 stay SysUserDao Add two methods to the interface .
void insertUserRole(SysUser entity) Add user related role information
void deleteUserRole(Integer id) Delete relevant roles according to users
3、 stay SysUserMapper.xml The corresponding sql.
4、 modify SysUserServiceImpl in , modify add()、edit() The implementation of the , Add related businesses of associated roles .
After adding users , Judge whether the list of relevant role numbers of the current user is empty , If it's not empty , Indicates that you need to add relevant role information .
After modifying the user , Judge whether the role of the current user is empty , If it's not empty , Delete the relevant role number ; Then judge whether the user related roles are empty sets , If there is a role number in the set , Indicates that you need to add role information .( Simply speaking : Modification of user roles , Delete all first , Add new )
summary :
Business when users add :
1. Determine if the user name is duplicate
2. New users
3. Judge whether the user has relevant role number information , If there is new relationship data
User editing business :
1. Edit user
2. Judge whether the user related role is empty , If not for null, Delete the relevant role number
3. Then judge whether the user related roles are empty and empty sets , If there is a role number in the set , Add relationship data
SysUser.java:
/** * System user entity class : Basic functions for user table CURD Implementation of operations */
public class SysUser {
// Other slightly
/* * Association attribute : Record the list of role numbers related to the current user */
private List<Integer> roleIdList;
public List<Integer> getRoleIdList() {
return roleIdList;
}
public void setRoleIdList(List<Integer> roleIdList) {
this.roleIdList = roleIdList;
}
}
SysUserDao Interface :
public interface SysUserDao extends BaseDao<SysUser> {
/* * Query according to user name * 1、 register : Duplicate user name check * 2、 The user login ( Refinement prompt use , First judge the user name , Then judge the password ) */
SysUser selectByUsername(String username);
/* * Add user related role information */
void insertUserRole(SysUser sysUser);
/* * Delete relevant roles according to user number */
void deleteUserRole(Integer id);
}
SysUserMapper.xml:
<insert id="insertUserRole" parameterType="com.newcapec.entity.SysUser">
insert into t_sys_user_role(user_id, role_id)
<foreach collection="roleIdList" open=" values" separator="," item="item">
(#{id}, #{item})
</foreach>
</insert>
<delete id="deleteUserRole" parameterType="java.lang.Integer">
delete from t_sys_user_role where user_id = #{id}
</delete>
SysUserServiceImpl.java:
/** * Business when users add : * 1. Determine if the user name is duplicate * 2. New users * 3. Judge whether the user has relevant role number information , If there is new relationship data */
@Override
public void add(SysUser entity) {
SysUser sysUser = findByUsername(entity.getUsername());
// Background verification , Guarantee safety , Prevent third-party tools from registering (PostMan)
if (sysUser == null) {
entity.setUserpwd(CommonConstant.PASSWORD_DEFAULT);
sysUserDao.insert(entity);
// Judge whether the list of relevant roles of the current user is empty , If it's not empty , Relevant role information needs to be added
//CollectionUtils yes Spring Provided , A method used to determine whether a set is empty or empty
if(!CollectionUtils.isEmpty(entity.getRoleIdList())){
sysUserDao.insertUserRole(entity);
}
}
}
/** * User editing business * 1. Edit user * 2. Judge whether the user related role is empty , If not for null, Delete the relevant role number * 3. Then judge whether the user related roles are empty and empty sets , If there is a role number in the set , Add relationship data */
@Override
public void edit(SysUser entity) {
SysUser sysUser = findByUsername(entity.getUsername());
if (sysUser != null) {
sysUserDao.update(entity);
// Judge whether the role of the current user is empty , If it's not empty , Delete the relevant role number ;
if(entity.getRoleIdList() != null){
sysUserDao.deleteUserRole(entity.getId());
// Then judge whether the user related roles are empty sets , If there is a role number in the set , Indicates that you need to add role information .
if(!CollectionUtils.isEmpty(entity.getRoleIdList())){
sysUserDao.insertUserRole(entity);
}
}
}
}
2.4.2 The front-end implementation
In the front page , When adding and modifying users , Show role checkbox .
Realize the idea :
1、 stay user.jsp Add and modify the pop-up box content of the page , Add a role related check box , But role data is dynamic , Then check boxes need to be loaded dynamically .
2、 stay user.jsp Query all role data in , Dynamically render character data .
3、 If it's a modification operation , After dynamically rendering the character data , Then do data echo .
4、 When the form submits data asynchronously , Will convert the data into json String to submit , Then the data submitted by the check box will only retain the last value , But what the server needs is an array , Then we need to deal with it manually , Before submitting data , Manually obtain the user's relevant role number and convert it into an array for submission .
5、 If it's a modification operation , Other data is echoed normally , But the user's role data cannot be echoed , Because we are based on id When querying users , There is no associated query role data , Modified according to id Query the user's sql that will do .
6、Layui When the form is echoed , Cannot assign an array to a form control , We need to assign values manually .
notes :layui Dynamic forms in , Must render refresh .
user.jsp:
<form id="dataForm" class="layui-form" lay-filter="dataForm">
<div class="layui-form-item">
<label class="layui-form-label"> role </label>
<div class="layui-input-block roleIdList">
<!-- Dynamically load role checkbox -->
</div>
</div>
</form>
<script type="text/javascript">
// Load module
layui.use(['table', 'form', 'layer'], function () {
// Other slightly
// Toolbar events
// notes :tool Is the toolbar event name ,test yes table Properties of the original container lay-filter=" Corresponding value "
table.on('tool(dataTable)', function (obj) {
var data = obj.data; // Get current row data
var layEvent = obj.event; // get lay-event Corresponding value ( It can also be in the header event The corresponding value of the parameter )
if (layEvent === 'remove') { // Delete
remove(data.id);
} else if (layEvent === 'edit') { // edit
// No more data echo here , Because you need to load the dynamic character data before echo
$("#dataFormUsername").prop('readonly', 'readonly');
$("#dataFormUsername").attr('lay-verify', '');
addOrEdit(data.id);
}
});
var window_index = -1; // Default form index value
function addOrEdit(id) {
// Page layer
layer.open({
type: 1,
title: id ? ' Modify the user ' : ' New users ',
content: $('#dataWindow'),
area: ['500px', '500px'], // Wide and high
btn: [' determine ', ' Cancel '],
yes: function (index) {
// If you set yes Callback , Manual closing is required
//layer.close(index);
window_index = index;
// Click the OK button , Submit form data
$("#submitBtn").click();
},
// Click the pop-up layer to display the subsequent events
success: function(){
// After the pop-up layer is displayed , Load all the role list data
loadRole(function(){
// If it's a modification operation , Then query the user's data and echo the data
if(id){
$.ajax('user/find/'+id, {
type: 'get',
success: function(res){
if(res.code == 200){
//formTest namely class="layui-form" Attribute of the element lay-filter="" Corresponding value
form.val('dataForm', res.data);
// Manually assign values to user related role information
$.each($(':checkbox[name="roleIdList"]'), function(){
this.checked = false;
var list = res.data.roleIdList;
if(list && list.length > 0){
for(var i in list){
if(list[i] == this.value){
this.checked = true;
}
}
}
});
// When the user is about to perform editing :
//1. The user name is read-only
$('#dataFormUsername').prop('readonly', 'readonly');
//2. User name cannot be uniquely verified
$('#dataFormUsername').attr('lay-verify', '');
form.render('checkbox', 'dataForm');
}
}
})
}
});
},
end: function () {
window_index = -1; // Reset form index defaults
// Reset form
$('#dataForm')[0].reset();
$("#dataFormUsername").prop('readonly', '');
$("#dataFormUsername").attr('lay-verify', 'required|usernameVerify');
}
});
}
// Add a form submission event
form.on('submit(submitBtn)', function (data) {
// All form fields of the current container , Name value pair form :{name: value}
console.log(data.field)
// Judge the form id Whether the field has a value , If it's worth it , Perform modification operations , Otherwise, execute new .
var url = 'user/add', method = 'post';
if (data.field.id) {
url = 'user/edit';
method = 'put';
}
//console.log(data);
// Get user related role number information manually
var array = [];
$.each($(':checkbox[name="roleIdList"]:checked'), function(){
array.push(this.value);
});
data.field.roleIdList = array;
$.ajax(url, {
type: method,
contentType: 'application/json',
data: JSON.stringify(data.field),
success: function (res) {
if (res.code == 200) {
// Close page layer
layer.close(window_index);
layer.msg(res.message);
tableReload();
}
}
})
return false; // Prevent form jump . If you need a form jump , Just remove this paragraph .
});
// Load all role data
function loadRole(follow){
$.ajax('role/find', {
type: 'get',
success: function(res){
var str = '';
res.data.forEach(function(item){
str += '<input type="checkbox" name="roleIdList" title="' + item.roleName + '" lay-skin="primary" value="' + item.id + '">';
});
$('.roleIdList').html(str);
form.render('checkbox', 'dataForm');
follow();
}
});
}
});
</script>
SysUserMapper.xml:
<resultMap id="BaseResultMap" type="com.newcapec.entity.SysUser">
<id column="id" property="id"/>
<result column="username" property="username"/>
<result column="mobile" property="mobile"/>
<result column="nickname" property="nickname"/>
<result column="email" property="email"/>
<result column="userpwd" property="userpwd"/>
<result column="salt" property="salt"/>
<result column="status" property="status"/>
</resultMap>
<resultMap id="SelectByIdResultMap" type="com.newcapec.entity.SysUser" extends="BaseResultMap">
<collection property="roleIdList" ofType="java.lang.Integer">
<constructor>
<arg column="role_id"/>
</constructor>
</collection>
</resultMap>
<select id="selectById" parameterType="java.lang.Integer" resultMap="SelectByIdResultMap">
select a.id, a.username, a.mobile, a.nickname, a.email, a.userpwd, a.salt, a.status, b.role_id from t_sys_user a
left join t_sys_user_role b on a.id = b.user_id
where a.id = #{id} and a.del=0
</select>
2.5 Associate permissions when adding and editing roles
2.5.1 Background implementation
When adding and editing roles , Associated operation role related permissions . A role can be assigned multiple permissions . Overall implementation ideas and 2.4 similar .
Realize the idea :
1、 stay SysRole Add associated attributes to entity classes , The attribute type is List<Integer> permissionIdList, Record the list of permission numbers related to the current role , And provide the corresponding getter and setter Method .
2、 stay SysRoleDao Add two methods to the interface .
void insertRolePermission(SysRole entity) Add role related permission information
void deleteRolePermission(Integer id) Delete relevant permission information according to the role
3、 stay SysRoleMapper.xml The corresponding sql.
4、 Modified according to id Query the role sql, Query the role information and the list of permission numbers related to the role .
5、 modify SysRoleServiceImpl in , modify add()、edit() The implementation of the , Add related businesses of associated permissions .
After adding roles , Judge whether the list of relevant permission numbers of the current role is empty , If it's not empty , Indicates that you need to add relevant permission information .
After modifying the role , Judge whether the permission list of the current role is empty , If it's not empty , Delete the relevant authority number ; Then judge whether the role related permissions are empty sets , If there is a permission number in the set , Indicates that you need to add permission information .( Simply speaking : Modification of role permissions , Delete all first , Add new )
SysRole.java:
public class SysRole {
// Other slightly
/* * Association attribute : Record the list of relevant permission numbers of the current role */
private List<Integer> permissionIdList;
public List<Integer> getPermissionIdList() {
return permissionIdList;
}
public void setPermissionIdList(List<Integer> permissionIdList) {
this.permissionIdList = permissionIdList;
}
}
SysRoleDao Interface :
public interface SysRoleDao extends BaseDao<SysRole> {
/* * Add role related permission information */
void insertRolePermission(SysRole sysRole);
/* * Delete relevant permission information according to the root role */
void deleteRolePermission(Integer id);
}
SysRoleMapper.xml:
<resultMap id="selectByIdResultMap" type="com.newcapec.entity.SysRole" extends="BaseResultMap">
<collection property="permissionIdList" ofType="java.lang.Integer">
<constructor>
<arg column="permission_id"/>
</constructor>
</collection>
</resultMap>
<select id="selectById" parameterType="java.lang.Integer" resultMap="selectByIdResultMap">
select a.id, a.role_code, a.role_name, a.description, b.permission_id from t_sys_role a
left join t_sys_role_permission b on a.id = b.role_id
where a.id = #{id} and a.del=0
</select>
<insert id="insertRolePermission" parameterType="com.newcapec.entity.SysRole">
insert into t_sys_role_permission(role_id, permission_id)
<foreach collection="permissionIdList" open=" values" separator="," item="item">
(#{id}, #{item})
</foreach>
</insert>
<delete id="deleteRolePermission" parameterType="java.lang.Integer">
delete from t_sys_role_permission where role_id = #{id}
</delete>
SysRoleServiceImpl.java:
@Override
public void add(SysRole entity) {
sysRoleDao.insert(entity);
if(!CollectionUtils.isEmpty(entity.getPermissionIdList())){
sysRoleDao.insertRolePermission(entity);
}
}
@Override
public void edit(SysRole entity) {
sysRoleDao.update(entity);
if(entity.getPermissionIdList() != null){
sysRoleDao.deleteRolePermission(entity.getId());
if(!CollectionUtils.isEmpty(entity.getPermissionIdList())){
sysRoleDao.insertRolePermission(entity);
}
}
}
2.5.2 The front-end implementation
In the front page , When adding and modifying roles , Show the permission tree structure .
Be careful : Roles are in the whole system , Just a few , Using the check box is not a problem . But there will be many permissions , If you use the check box , It's not reasonable to .
Realize the idea :
1、 stay role.jsp Add and modify the pop-up box content of the page , Add a permission , But the permission data is dynamic .
2、 stay role.jsp Query all permission list data in , Show in a tree structure ( Need to load layui Of tree modular ).
3、 If it's a modification operation , After dynamically rendering the permission tree structure data , Then do data echo .
4、 The data obtained from the background query does not conform to layui tree Data structure of , Then we need to process the data .
4.1 Convert the background response data into layui in tree The data structure required by the component ,layui tree Components need to id、title、spread、children etc. , But the background response data does not contain these data .
4.2 Convert data in list structure into data in tree structure .
5、 Render the parsed tree structure data to the specified elements .
6、 When you submit the form , You need to manually add the role related permission number data ( Because the tree structure is not a form control ).
7、 Modify the operating , The data echo of the form will not echo the tree structure , Just call the tree node setChecked that will do .
Be careful : because layui The reason for the tree component of , As long as the parent node is selected , Then all child nodes will be checked by default , Then we need data filtering , Only check the button permission .
role.jsp:
<div class="layui-form-item">
<label class="layui-form-label"> jurisdiction </label>
<div class="layui-input-block">
<div id="permissionTree"></div>
</div>
</div>
<script type="text/javascript" src="static/js/tool.js"></script>
<script type="text/javascript">
layui.use(['table', 'form', 'layer', 'tree'], function () {
var form = layui.form,
layer = layui.layer,
table = layui.table,
tree = layui.tree,
$ = layui.$;
// Line tool Events
// notes :tool Is the toolbar event name ,test yes table Properties of the original container lay-filter=" Corresponding value "
table.on('tool(tab)', function(obj) {
// Get current row data
var data = obj.data;
// get lay-event Corresponding value ( It can also be in the header event The corresponding value of the parameter )
var layEvent = obj.event;
if(layEvent == 'edit'){
// Click the edit button
addOrEdit(data.id);
}else if(layEvent == 'remove'){
// Click the delete button
remove(data.id);
}
});
// Add or modify
var window_index = -1;
function addOrEdit(id){
layer.open({
type: 1,
title: id ? ' Role editor ' : ' Role addition ',
content: $('#dataWindow'),
btn: [' determine ', ' Cancel '],
// Click the OK button to the event
yes: function(index){
window_index = index
$('.submitBtn').click();
},
// Click the pop-up layer to display the subsequent events
success: function(){
loadPermission(function(permissions){
if(id){
$.ajax('role/find/'+id, {
type: 'get',
success: function(res){
if(res.code == 200){
//formTest namely class="layui-form" Attribute of the element lay-filter="" Corresponding value
form.val('dataForm', res.data);
var array = [];
// Filter the list of permission numbers owned by the current role , Keep only type=3 Permission number of
res.data.permissionIdList.forEach(function(item){
for(var i in permissions){
if(permissions[i].id == item && permissions[i].type == 3){
array.push(item);
break;
}
}
});
tree.setChecked('permissionTree', array);
}
}
})
}
});
},
// Click the pop-up layer to hide the event
end: function(){
window_index = -1;
// Empty the form
$('#dataForm')[0].reset();
}
});
}
// Form submit event
form.on('submit(submitBtn)', function(data){
// All form fields of the current container , Name value pair form :{name: value}
var url = 'role/add';
var method = 'post';
if(data.field.id){
//id Parameter data indicates that the current operation is edit , Otherwise, it is new
url = 'role/edit';
method = 'put';
}
// Manually add role related permission number data
var array = [];
var checkData = treeToData(tree.getChecked('permissionTree'));
checkData.forEach(function(item){
array.push(item.id);
});
data.field.permissionIdList = array;
$.ajax(url, {
type: method,
contentType: 'application/json',
data: JSON.stringify(data.field),
success: function(res){
if(res.code = 200){
layer.close(window_index);
layer.msg(res.message);
tableReload();
}
}
});
// Prevent form jump . If you need a form jump , Just remove this paragraph .
return false;
});
// Load role list data
function loadPermission(follow){
$.ajax('permission/find', {
type: 'get',
success: function(res){
//1. Convert data to layui in tree Data required by the component
res.data.forEach(function(item){
item.title = item.name;
item.spread = true;
});
//2. Convert list data into tree structure data
var treeData = dataToTree(res.data);
//3. Tree component initialization
// Tree component data loading
tree.render({
id: 'permissionTree',
elem: '#permissionTree',
showCheckbox: true,
showLine: false,
data: treeData
});
follow(res.data);
}
});
}
});
</script>
2.6 The user login
2.6.1 Background implementation
1、SysUserDao Has been defined in SysUser selectByUsername(String username) Method , Then we can start from service Start writing .
2、 stay SysUserService Interface UserInfo login(String username,String userpwd);
Be careful :UserInfo Entity classes are used to store user login information ,SysUser It is the basic function for user table CURD Operation of the .
3、 stay SysUserServiceImpl Implement the specific login business in the implementation class .
1. According to the user name ( User ID ), Query relevant records in the database
2. Judge whether the queried user is null
3. If null, Indicates that the user name provided by the current user is incorrect
4. If not for null, According to the password provided by the user ( User credentials ) Compare the passwords stored in the database
5. If not, the password provided by the user is incorrect
6. If it's consistent, return UserInfo object
4、 Definition LoginController, Login related requests are defined in the controller .
UserInfo Entity class :
package com.newcapec.entity;
import java.util.List;
/** * User login information object */
public class UserInfo {
private Integer id;
private String username;
private String mobile;
private String nickname;
private String email;
private String userpwd;
private String salt;
private String status;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getMobile() {
return mobile;
}
public void setMobile(String mobile) {
this.mobile = mobile;
}
public String getNickname() {
return nickname;
}
public void setNickname(String nickname) {
this.nickname = nickname;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getUserpwd() {
return userpwd;
}
public void setUserpwd(String userpwd) {
this.userpwd = userpwd;
}
public String getSalt() {
return salt;
}
public void setSalt(String salt) {
this.salt = salt;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
}
SysUserService Interface :
public interface SysUserService extends BaseService<SysUser> {
SysUser findByUsername(String username);
UserInfo login(String username, String userpwd);
}
SysUserServiceImpl Implementation class :
/** * Sign in * 1. According to the user name ( User ID ), Query relevant records in the database * 2. Judge whether the queried user is null * 3. If null, Indicates that the user name provided by the current user is incorrect * 4. If not for null, According to the password provided by the user ( User credentials ) Compare the passwords stored in the database * 5. If not, the password provided by the user is incorrect * 6. If it's consistent, return UserInfo object */
@Override
public UserInfo login(String username, String userpwd) {
SysUser sysUser = sysUserDao.selectByUsername(username);
if(sysUser != null){
if(userpwd.equals(sysUser.getUserpwd())){
UserInfo userInfo = new UserInfo();
//spring A tool class is provided in BeanUtils, Provide attribute value copy function
//copyProperties( Source object , Target audience )
// requirement : Property names are consistent
BeanUtils.copyProperties(sysUser, userInfo);
return userInfo;
}
}
return null;
}
LoginController.java:
package com.newcapec.controller;
import com.newcapec.constant.SystemCode;
import com.newcapec.entity.UserInfo;
import com.newcapec.service.SysUserService;
import com.newcapec.utils.Result;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpSession;
@RestController
@RequestMapping("/auth")
public class LoginController {
@Autowired
private SysUserService sysUserService;
/** * Login interface * call Service Medium login Method * If the return value is null, Indicates that the user name or password is incorrect * If the return value is not null * 1. Put user information UserInfo Objects stored in HttpSession in * 2. Return the result of successful login ( User information can be sent to the front end ) * * Be careful : * Login is usually for password security , use post request */
@PostMapping("/login")
public Result login(@RequestBody UserInfo userInfo, HttpSession session) {
UserInfo dbUserInfo = sysUserService.login(userInfo.getUsername(), userInfo.getUserpwd());
if (dbUserInfo != null) {
session.setAttribute("userInfo", dbUserInfo);
return Result.success(dbUserInfo);
}
return Result.error(SystemCode.USERNAME_ERROR.getCode(), SystemCode.USERNAME_ERROR.getMessage(), null);
}
/** * Login interface */
@GetMapping("/logout")
public Result logout(HttpSession session) {
session.removeAttribute("userInfo");
session.invalidate();
return Result.success();
}
}
2.6.2 The front-end implementation
Realize the idea :
1、 stay views Create under directory login.jsp page , And introduce layui relevant css and js file .
2、 The homepage of the normal background management system , It should be the login page , So modify web.xml Configuration in .
3、 adopt HTML/CSS Write static page effects .
4、 Send asynchronous login request .
1. If the username and password are correct , Jump to home page .
2. If the user name or password is incorrect , Then the pop-up box will prompt .
5、 After login , Jump page , Dynamically display the nickname of the login user .
6、 stay index.jsp Page exit system link binding event , When the event triggers , Ask whether you want to exit the system ? If you click OK , Then send an asynchronous request to log out , Exit and jump to the login page .
notes : If the front page is not jsp、 Template engine and other dynamic pages , But static pages , Then we can use sessionStoreage To achieve .
login.jsp:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<base href="${pageContext.request.contextPath}/">
<title> Background management system </title>
<link rel="stylesheet" href="static/layui/css/layui.css">
<style type="text/css">
body {
margin: 0;
padding: 0;
height: 100vh;
/* flex Fluid layout */
display: flex;
/*flex-flow: column nowrap;*/
justify-content: center;
align-items: center;
background-image: url(static/images/login_bg.jpg);
}
.login-page {
width: 450px;
background-color: #ffffff;
border-radius: 10px;
padding: 30px 20px;
}
.login-header {
text-align: center;
font-size: 20px;
font-weight: bold;
}
</style>
</head>
<body>
<div class="login-page">
<form class="layui-form">
<div class="layui-form-item">
<div class="login-header"> please    deng    record </div>
</div>
<div class="layui-form-item">
<input type="text" name="username" lay-verify="required" placeholder=" user name " class="layui-input">
</div>
<div class="layui-form-item">
<input type="password" name="userpwd" lay-verify="required" placeholder=" password " class="layui-input">
</div>
<div class="layui-form-item">
<button class="layui-btn layui-btn-fluid" lay-submit lay-filter="submitBtn"> Sign in </button>
</div>
</form>
</div>
<script type="text/javascript" src="static/layui/layui.js"></script>
<script>
layui.use(['form', 'layer'], function () {
var form = layui.form,
layer = layui.layer,
$ = layui.$;
// Submit login
form.on('submit(submitBtn)', function (data) {
$.ajax('auth/login', {
type: 'post',
contentType: 'application/json',
data: JSON.stringify(data.field),
success: function (res) {
if (res.code == 200) {
// If the front page adopts pure static page , Store the user information returned from the background response in the front-end cache
// sessionStorage.setItem(key, value); save
// sessionStorage.getItem(key); take
// sessionStorage.removeItem(key); Delete
sessionStorage.setItem('userInfo', JSON.stringify(res.data));
// Page Jump
location.href = 'page/index';
} else {
layer.msg(res.message);
}
}
});
return false;
});
});
</script>
</body>
</html>
index.jsp:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<base href="${pageContext.request.contextPath}/">
<title> Background management system </title>
<!-- introduce Layui The style file -->
<link rel="stylesheet" href="static/layui/css/layui.css">
</head>
<body>
<!-- introduce layui Classic layout and revision -->
<div class="layui-layout layui-layout-admin">
<!-- Page header -->
<div class="layui-header">
<div class="layui-logo layui-hide-xs layui-bg-black"> Background management system </div>
<ul class="layui-nav layui-layout-right">
<li class="layui-nav-item layui-hide layui-show-md-inline-block">
<a href="javascript:;">
<img src="//tva1.sinaimg.cn/crop.0.0.118.118.180/5db11ff4gw1e77d3nqrv8j203b03cweg.jpg"
class="layui-nav-img">
<!-- Get the nickname of the login user on the dynamic page -->
<%--${sessionScope.userInfo==null?' nothing ':sessionScope.userInfo.nickname}--%>
<!-- Get the nickname of the login user on the static page -->
<span class="user-info"></span>
</a>
<dl class="layui-nav-child">
<dd><a href=""> Personal information </a></dd>
<dd><a href=""> System settings </a></dd>
<dd><a href="javascript:void(0);" class="logoutBtn"> Exit the system </a></dd>
</dl>
</li>
</ul>
</div>
<div class="layui-side layui-bg-black">
<div class="layui-side-scroll">
<!-- Left navigation area ( Compatible layui Existing vertical navigation ) -->
<ul class="layui-nav layui-nav-tree" lay-filter="test">
<li class="layui-nav-item layui-nav-itemed">
<a class="" href="javascript:;"> System management </a>
<dl class="layui-nav-child">
<dd><a href="page/sys/user" target="mainFrame"> User list </a></dd>
<dd><a href="page/sys/role" target="mainFrame"> Character list </a></dd>
<dd><a href="page/sys/permission" target="mainFrame"> Permission list </a></dd>
</dl>
</li>
<li class="layui-nav-item">
<a href="javascript:;"> The business management </a>
<dl class="layui-nav-child">
<dd><a href="student/find" target="mainFrame"> Student list </a></dd>
<dd><a href="javascript:;"> List of employees </a></dd>
<dd><a href="javascript:;"> Department list </a></dd>
</dl>
</li>
</ul>
</div>
</div>
<div class="layui-body">
<!-- Content subject area -->
<iframe name="mainFrame" frameborder="0" style="width:100%;height: 100%" src="page/welcome"></iframe>
</div>
<div class="layui-footer">
<!-- Bottom fixed area -->
Bottom fixed area
</div>
</div>
<!-- introduce layui.js file -->
<script type="text/javascript" src="static/layui/layui.js"></script>
<script>
layui.use(['layer', 'element'], function () {
var element = layui.element,
layer = layui.layer,
$ = layui.$;
// Get the data in the front-end cache
var userInfo = JSON.parse(sessionStorage.getItem('userInfo'));
if(userInfo && userInfo.nickname){
$('.user-info').html(userInfo.nickname);
}else {
$('.user-info').html(' Not logged in ');
}
$('.logoutBtn').click(function () {
layer.confirm(' Are you sure you want to exit the system ?', function () {
$.ajax('auth/logout', {
type: 'get',
success: function (res) {
if (res.code == 200) {
// Clear cache
sessionStorage.removeItem('userInfo');
location.href = 'page/login';
}
}
})
});
});
});
</script>
</body>
</html>
2.6.3 Authentication interceptor
Realize the idea :
1、 Definition SpringMVC Interceptor LoginInterceptor( Realization HandlerInterceptor Interface ), In the interceptor preHandle Method for user identity authentication . The package where the interceptor is located :interceptor.
2、 from session Get user login information in the domain .
1. If not for null, The release .
2. If null, The intercept . There are two ways :
Mode one : Page Jump . Redirect to the login page through the response object . However, this method has certain limitations , If it is a development mode with front and rear ends separated , It should be the jump of the front-end control page , Instead of deciding the jump of the page in the background .
Mode two : Respond to json data , Prompt not logged in .
3、 Configure interceptors , Set interception request and release request .
4、 On the front page , Get the return data of the asynchronous request , If not 200, Then give the corresponding prompt .
5、 On the front page , Determine whether to log in , If for login , Go to the login page .
Mode one : from session Get user login information in the domain , If you are not logged in , Then go to the login page .
Mode two : Get user login information from the front-end cache , If there is no cached data , Then go to the login page .
LoginInterceptor.java:
package com.newcapec.interceptor;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.newcapec.constant.SystemCode;
import com.newcapec.utils.Result;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
/** * User authentication ( The user login ) Interceptor */
public class LoginInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {
// obtain HttpSession object
HttpSession session = httpServletRequest.getSession();
// from session Get user login information in the domain
Object userInfo = session.getAttribute("userInfo");
// Judge whether the user login information exists
if (userInfo == null) {
// Page Jump
//httpServletResponse.sendRedirect(httpServletRequest.getContextPath() + "/page/login");
// Set response content type
httpServletResponse.setContentType("application/json;charset=utf-8");
// Respond to users json data , Prompt not logged in
Result result = Result.error(SystemCode.NOT_LOGIN.getCode(), SystemCode.NOT_LOGIN.getMessage(), null);
// Manually convert the custom response format object to json character string : jackson
ObjectMapper objectMapper = new ObjectMapper();
String resultStr = objectMapper.writeValueAsString(result);
httpServletResponse.getWriter().write(resultStr);
return false;
}
return true;
}
@Override
public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
}
@Override
public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
}
}
springmvc.xml:
<!-- Configure interceptors -->
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<!-- Dynamic page Jump request and static resource mapping request -->
<mvc:exclude-mapping path="/page/**"/>
<mvc:exclude-mapping path="/static/**"/>
<mvc:exclude-mapping path="/auth/login"/>
<bean class="com.newcapec.interceptor.LoginInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
index.jsp:
<script>
layui.use(['layer', 'element'], function () {
var element = layui.element,
layer = layui.layer,
$ = layui.$;
// Judge whether the user logs in on the current page
/*var obj = '${sessionScope.userInfo}';
if(!obj){
location.href = 'page/login';
}*/
// Get the data in the front-end cache
var userInfo = JSON.parse(sessionStorage.getItem('userInfo'));
if(!userInfo){
location.href = 'page/login';
}else if(userInfo && userInfo.nickname){
$('.user-info').html(userInfo.nickname);
}
$('.logoutBtn').click(function () {
layer.confirm(' Are you sure you want to exit the system ?', function () {
$.ajax('auth/logout', {
type: 'get',
success: function (res) {
if (res.code == 200) {
// Clear cache
sessionStorage.removeItem('userInfo');
location.href = 'page/login';
}else if(res.code == 404){
layer.msg(res.message);
}
}
})
});
});
});
</script>
sys Related pages :
// Judge whether the user logs in on the current page
var userInfo = sessionStorage.getItem('userInfo');
if(!userInfo){
location.href = 'page/login';
}
2.6.4 Implementation of dynamic menu
Realize the idea :
1、 The permission list data is consistent with the background menu data , Insert the business management directory in the permission 、 Student list / List of employees / Department list menu 、 There is a query button permission under each list .
2、 Configure test data .
Configure role permission data :admin The role has all permissions 、user The role has all business management and user query permissions .
Configure user role data :admin Users have administrators 、 Ordinary user role 、 Tom has ordinary user roles .
3、 Improve the pages corresponding to the employee menu and department menu , And configure the page Jump path .
stay views Create below emp/find.jsp、dept/find.jsp, The content of the page doesn't matter .
stay SystemController Configure page Jump path .
4、 Configure the access path of permissions .
5、 According to the user id Query the permissions you have , Then it involves the permission table 、 Role authority middle table 、 User role middle table three table associated query .
1. stay SysPermissionDao In the definition of List<SysPermission> selectByUserId(@Param("userId") Integer userId, @Param("type") String type) Method , This method is based on the user ID Query the list of permissions owned by the current user .
If it's delivered type by 3, Filter button type permissions , Dynamic menu use .
If it's delivered type by null, Then query all permission types . Authorization authentication use .
2. stay SysPermissionMapper.xml It defines the corresponding sql.
3. stay SysPermissionService In the definition of List<SysPermission> findMenu(Integer userId) Method .
4. stay SysPermissionServiceImpl To achieve specific business .
5. stay SysPermissionController Define request mapping , from session Get the currently logged in user in the domain , Get the corresponding permission menu .
6、 stay index.jsp The page sends asynchronous requests , Get the permission of the currently logged in user , Dynamically generate menus .
SystemController.java:
/** * The processor used to realize page Jump */
@Controller
@RequestMapping("/page")
public class SystemController {
@GetMapping("/stu/add")
public String stuAdd() {
return "stu/add";
}
@GetMapping("/welcome")
public String welcome() {
return "welcome";
}
@GetMapping("/sys/user")
public String sysUser() {
return "sys/user";
}
@GetMapping("/sys/role")
public String sysRole() {
return "sys/role";
}
@GetMapping("/sys/permission")
public String sysPermission() {
return "sys/permission";
}
@GetMapping("/emp")
public String emp() {
return "emp/find";
}
@GetMapping("/dept")
public String dept() {
return "dept/find";
}
@GetMapping("/index")
public String index() {
return "index";
}
@GetMapping("/login")
public String login() {
return "login";
}
}
index.jsp:
<li class="layui-nav-item">
<a href="javascript:;"> The business management </a>
<dl class="layui-nav-child">
<dd><a href="student/find" target="mainFrame"> Student list </a></dd>
<dd><a href="page/emp" target="mainFrame"> List of employees </a></dd>
<dd><a href="page/dept" target="mainFrame"> Department list </a></dd>
</dl>
</li>
Access path of permission :
SysPermissionDao.java:
public interface SysPermissionDao extends BaseDao<SysPermission> {
/** * According to the user ID Query the list of permissions owned by the current user * Parameters userId, Users to query id * Parameters type, The type of menu . * If it's delivered type by 3, Filter button type permissions , Dynamic menu use * If it's delivered type by null, Then query all permission types . Authorization authentication use */
List<SysPermission> selectByUserId(@Param("userId") Integer userId, @Param("type") String type);
}
SysPermissionMapper.xml:
<select id="selectByUserId" parameterType="java.util.HashMap" resultMap="BaseResultMap">
select distinct a.id, a.name, a.type, a.url, a.percode, a.parent_id, a.sort from t_sys_permission a
join t_sys_role_permission b on a.id = b.permission_id
join t_sys_user_role c on b.role_id = c.role_id
<where>
c.user_id = #{userId} and a.del = 0
<if test="type != null">
and a.type != 3
</if>
</where>
order by a.sort
</select>
SysPermissionService.java:
public interface SysPermissionService extends BaseService<SysPermission> {
List<SysPermission> findMenu(Integer userId);
}
SysPermissionServiceImpl.java:
@Override
public List<SysPermission> findMenu(Integer userId) {
return sysPermissionDao.selectByUserId(userId, "3");
}
SysPermissionController.java:
/** * Query the menu of the currently logged in user */
@GetMapping("/findMenu")
public Result findMenu(HttpSession session){
// from session Get the current login user in the domain
UserInfo userInfo = (UserInfo) session.getAttribute("userInfo");
List<SysPermission> menus = sysPermissionService.findMenu(userInfo.getId());
return Result.success(menus);
}
index.jsp:
<!-- Left navigation area ( Compatible layui Existing vertical navigation ) -->
<ul class="layui-nav layui-nav-tree treeMenu" lay-filter="test">
<!-- Dynamic rendering of menu data -->
</ul>
<script type="text/javascript" src="static/js/tool.js"></script>
<script>
// Initialize the menu list of the current user
$.ajax('permission/findMenu', {
type: 'get',
success: function(res){
if(res.code == 200){
var menus = dataToTree(res.data);
console.log('===> Menu data :', menus);
var str = '';
menus.forEach(function(item){
str += '<li class="layui-nav-item layui-nav-itemed">';
str += '<a class="" href="javascript:;">' + item.name + '</a>';
if(item.children && item.children.length > 0){
str += '<dl class="layui-nav-child">';
item.children.forEach(function(item2){
str += '<dd><a href="' + item2.url + '" target="mainFrame">' + item2.name + '</a></dd>';
});
str += '</dl>';
}
str += '</li>';
});
$('.treeMenu').html(str);
//element.render('nav', 'test');
}else{
layer.msg(res.message);
}
}
});
</script>
2.7 Authority identification
Implementation of dynamic menu , It only realizes the menu displayed after the user logs in , The menu with permission is displayed , Menus without permission are not displayed . But if after logging in , Know about other pages url, You can also operate other non permission menus .
such as tom user , There is no permission to operate roles and permissions , But you can enter the address in the address bar to access .
http://localhost:8080/ssm/page/sys/permission
http://localhost:8080/ssm/page/sys/role
Realize the idea :
1. stay SysPermissionService In the definition of List<SysPermission> findByUserId(Integer userId) Method , It is used to query all the permission lists of users .
2. stay SysPermissionServiceImpl To achieve specific business .
3. stay SysUserServiceImpl Of login In the method , When the user logs in successfully , Query all permissions owned by the current user , And assign it to userInfo object .
4. Definition PermissionInterceptor Authorization interceptor , Judge a request , Whether the current user has permission to access .
5. Configure interceptors .
Be careful : Be sure to configure it after logging in the interceptor .
SysPermissionService.java:
public interface SysPermissionService extends BaseService<SysPermission> {
List<SysPermission> findMenu(Integer userId);
List<SysPermission> findByUserId(Integer userId);
}
SysPermissionServiceImpl.java:
@Override
public List<SysPermission> findByUserId(Integer userId) {
return sysPermissionDao.selectByUserId(userId, null);
}
SysUserServiceImpl.java:
@Autowired
private SysPermissionService sysPermissionService;
@Override
public UserInfo login(String username, String userpwd) {
SysUser sysUser = sysUserDao.selectByUsername(username);
if(sysUser != null){
if(userpwd.equals(sysUser.getUserpwd())){
UserInfo userInfo = new UserInfo();
//spring A tool class is provided in BeanUtils, Provide attribute value copy function
//copyProperties( Source object , Target audience )
// requirement : Property names are consistent
BeanUtils.copyProperties(sysUser, userInfo);
// Query all permissions owned by the current user
List<SysPermission> permissionList = sysPermissionService.findByUserId(userInfo.getId());
userInfo.setPermissionList(permissionList);
return userInfo;
}
}
return null;
}
PermissionInterceptor.java:
package com.newcapec.interceptor;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.newcapec.constant.SystemCode;
import com.newcapec.entity.SysPermission;
import com.newcapec.entity.UserInfo;
import com.newcapec.utils.Result;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.util.List;
/** * User authentication interceptor : Judge a request , Whether the current user has permission to access * Through the path url Intercept to authenticate permissions */
public class PermissionInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {
HttpSession session = httpServletRequest.getSession();
Object obj = session.getAttribute("userInfo");
// Judge whether the user login information exists
if (obj instanceof UserInfo) {
UserInfo userInfo = (UserInfo) obj;
// Get the permission list of the currently logged in user
List<SysPermission> permissionList = userInfo.getPermissionList();
// Gets the current request path
String url = httpServletRequest.getServletPath();
System.out.println(" The path of this request :" + url);
// Query the data matching the current request path in the permission list of the currently logged in user
// If it is queried, it means that the user has permission to access
// If no query is found, the user does not have permission to access
for (SysPermission sysPermission : permissionList) {
System.out.println(" Permission path :" + sysPermission.getUrl());
if (url.contains(sysPermission.getUrl()) && !sysPermission.getUrl().equals("")) {
return true;
}
}
httpServletResponse.setContentType("application/json;charset=utf-8");
// Respond to users json data , Prompt not logged in
Result result = Result.error(SystemCode.NO_PERMISSION.getCode(), SystemCode.NO_PERMISSION.getMessage(), null);
// Manually convert the custom response format object to json character string : jackson
ObjectMapper objectMapper = new ObjectMapper();
String resultStr = objectMapper.writeValueAsString(result);
httpServletResponse.getWriter().write(resultStr);
}
return false;
}
@Override
public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
}
@Override
public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
}
}
springmvc.xml:
<!-- Configure interceptors -->
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<!-- Dynamic page Jump request and static resource mapping request -->
<mvc:exclude-mapping path="/page/**"/>
<mvc:exclude-mapping path="/static/**"/>
<mvc:exclude-mapping path="/auth/login"/>
<bean class="com.newcapec.interceptor.LoginInterceptor"/>
</mvc:interceptor>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<mvc:exclude-mapping path="/page/login"/>
<mvc:exclude-mapping path="/page/index"/>
<mvc:exclude-mapping path="/page/welcome"/>
<mvc:exclude-mapping path="/static/**"/>
<mvc:exclude-mapping path="/auth/**"/>
<mvc:exclude-mapping path="/permission/findMenu"/>
<bean class="com.newcapec.interceptor.PermissionInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
边栏推荐
- PMP experience learning and sharing process
- Selenium mouse sliding operation event
- Serializer & modelserializer of DRF serialization and deserialization
- 2021 year end summary
- Postman interface debugging method
- flex弹性布局
- 【SVN】SVN是什么?怎么使用?
- Confitest of fixture py
- shake数据库中怎么使用Mongo-shake实现MongoDB的双向同步啊?
- STM32的时钟系统
猜你喜欢
Locust performance test 4 (custom load Policy)
Register address name mapping
华为HCIP-DATACOM-Core_03day
JMeter JDBC batch references data as input parameters (the simplest method for the whole website)
Jenkins task grouping
信息安全实验四:Ip包监视程序实现
串口實驗——簡單數據收發
Mysql database lock learning notes
STM32 clock system
Regular matching starts with XXX and ends with XXX
随机推荐
超十万字_超详细SSM整合实践_手动实现权限管理
Do you have any certificates with high gold content?
Kubernetes cluster capacity expansion to add node nodes
Leetcode刷题记录(数组)组合总和、组合总和 II
PMP certificate preparation experience sharing
在EXCEL写VBA连接ORACLE并查询数据库中的内容
The essence of high availability
Huawei HCIP - datacom - Core 03 jours
十二、排序
SAP MM STO单据的外向交货单创建后新加ITEM?
信息安全实验一:DES加密算法的实现
Unity shader (to achieve a simple material effect with adjustable color attributes only)
Leetcode question brushing record (array) combination sum, combination sum II
数据库多表关联查询问题
C语言指针(中篇)
数据在内存中的存储
Final keyword
Variable parameter of variable length function
When inputting an expression in the input box, an error is reported: incorrect string value:'\xf0\x9f... ' for column 'XXX' at row 1
Jenkins+ant+jmeter use