相关链接:
MyEclipse CI 2018.9.0 配置 Apache Maven 3.5.4
在MyEclipse CI 2018.9.0 中使用 Maven 3.5.4 创建Maven项目
在MyEclipse中使用SVN提交(自动忽略 .settings .project .classpath等)、检出(无.settings .project .classpath文件等)Maven代码
Dynamic Web Module
4.0
Java
1.8
JavaScript
1.0
JSTL Libraries
1.2.4
MyEclipse Server Library
Apache Tomcat v9.0
项目结构预览: 配置pom.xml: <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>net.csdn</groupId> <artifactId></artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>war</packaging> <name></name> <!-- 阿里云maven代码库 --> <repositories> <repository> <id>aliyun</id> <name>aliyun</name> <url>http://maven.aliyun.com/nexus/content/groups/public</url> </repository> </repositories> <!-- 阿里云maven代码库 --> <properties> <!-- Spring框架jar包版本 --> <!-- 2018年7月26日 5.0.8.RELEASE 截止2018-09-06为最新版 --> <spring.version>5.0.8.RELEASE</spring.version> <!-- 启用@AspectJ支持 --> <!-- 2018年4月20日 1.9.1 截止2018-09-06为最新版 --> <aspectjweaver.version>1.9.1</aspectjweaver.version> <!-- mchange c3p0 --> <!-- 2015年12月9日 0.9.5.2 截止2018-09-06为最新版 --> <c3p0.version>0.9.5.2</c3p0.version> <!-- 2018年2月2日 0.2.15 截止2018-09-06为最新版 --> <mchange-commons.version>0.2.15</mchange-commons.version> <!-- mchange c3p0 --> <!-- MyBatis --> <!-- 2018年3月11日 3.4.6 截止2018-09-06为最新版 --> <mybatis.version>3.4.6</mybatis.version> <!-- MyBatis整合Spring中间件jar包 --> <!-- 2018年3月14日 1.3.2 截止2018-09-06为最新版 --> <mybatis-spring.version>1.3.2</mybatis-spring.version> <!-- mysql 数据库驱动 --> <!-- 2018年6月28日 8.0.12 截止2018-09-06为最新版 --> <mysql-connector.version>8.0.12</mysql-connector.version> <!-- log4j2 --> <!-- 2018年7月30日 2.11.1 截止2018-09-06为最新版 --> <log4j2.version>2.11.1</log4j2.version> <!-- slf4j --> <!-- 2017年3月16日 1.7.25 截止2018-09-06为最新版 --> <slf4j.version>1.7.25</slf4j.version> <!-- commons-lang3 --> <!-- 2018年8月16日 3.8 截止2018-09-06为最新版 --> <!-- 工具类 --> <commons-lang3.version>3.8</commons-lang3.version> <!-- commons-text --> <!-- 工具类 --> <!-- 2018年6月9日 截止2018-09-06为最新版 --> <commons-text.version>1.4</commons-text.version> <!-- springfox --> <!-- 2018年6月23日 2.9.2 截止2018-09-06为最新版 --> <springfox-swagger2.version>2.9.2</springfox-swagger2.version> <!-- javax/servlet/jsp/jstl/core/Config --> <!-- 2006年5月12日 1.2 --> <jstl.version>1.2</jstl.version> <!-- jetty-webapp --> <!-- 2018年8月30日 9.4.12.v20180830 截止2018-09-06为最新版 --> <jetty-webapp.version>9.4.12.v20180830</jetty-webapp.version> <!-- gson --> <!-- 2018年5月22日 2.8.5 截止2018-09-06为最新版 --> <gson.version>2.8.5</gson.version> <!-- json --> <!-- 还需要commons-lang,已被引入 --> <commons-beanutils.version>1.9.3</commons-beanutils.version> <commons-collections.version>3.2.2</commons-collections.version> <commons-logging.version>1.2</commons-logging.version> <ezmorph.version>1.0.6</ezmorph.version> <json.version>2.4</json.version> <!-- github验证码 --> <patchca.version>0.0.1</patchca.version> </properties> <dependencies> <!-- ++++++++++++++++++++++++++++++ spring、spring mvc ++++++++++++++++++++ --> <!-- spring 视图解析器 5.0.8.RELEASE --> <!-- 相关依赖(自动引入5.0.8.RELEASE): spring-aop-、spring-beans-、spring-context-、spring-core-、spring-expression-、spring-jcl-、spring-web- --> <!-- 同spring-websocket --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>${spring.version}</version> </dependency> <!-- spring JDBC事务管理器 5.0.8.RELEASE --> <!-- 相关依赖(自动引入5.0.8.RELEASE):spring-beans、spring-core、spring-jcl、spring-tx --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>${spring.version}</version> </dependency> <!-- 相关依赖(自动引入5.0.8.RELEASE):spring-aop、spring-beans、spring-context、spring-core、spring-expression、spring-jcl、spring-web、 --> <!-- 同spring-webmvc --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-websocket</artifactId> <version>${spring.version}</version> </dependency> <!-- 相关依赖(自动引入5.0.8.RELEASE):spring-beans-、spring-core-、spring-jcl- --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-messaging</artifactId> <version>${spring.version}</version> </dependency> <!-- ++++++++++++++++++++++++++++++ aspectjweaver ++++++++++++++++++++ --> <!-- aspectjweaver --> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>${aspectjweaver.version}</version> </dependency> <!-- ++++++++++++++++++++++++++++++ c3p0 ++++++++++++++++++++ --> <!-- c3p0 --> <!-- mchange c3p0 0.9.5.2 --> <!-- 相关依赖(自动引入0.2.11):mchange-commons-java- --> <dependency> <groupId>com.mchange</groupId> <artifactId>c3p0</artifactId> <version>${c3p0.version}</version> </dependency> <!-- mchange commons --> <dependency> <groupId>com.mchange</groupId> <artifactId>mchange-commons-java</artifactId> <version>${mchange-commons.version}</version> </dependency> <!-- c3p0 --> <!-- ++++++++++++++++++++++++++++++ mybatis ++++++++++++++++++++ --> <!-- MyBatis --> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>${mybatis.version}</version> </dependency> <!-- ++++++++++++++++++++++++++++++ mybatis-spring ++++++++++++++++++++ --> <!-- MyBatis整合Spring中间件jar包 --> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis-spring</artifactId> <version>${mybatis-spring.version}</version> </dependency> <!-- ++++++++++++++++++++++++++++++ mysql ++++++++++++++++++++ --> <!-- mysql 数据库驱动 8.0.12 --> <!-- 相关依赖(自动引入2.6.0):protobuf-java- --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>${mysql-connector.version}</version> </dependency> <!-- ++++++++++++++++++++++++++++++ log4j2 ++++++++++++++++++++ --> <!-- log4j2 2.11.1 --> <!-- 相关依赖(自动引入2.11.1):log4j-core、log4j-api --> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-web</artifactId> <version>${log4j2.version}</version> </dependency> <!-- ++++++++++++++++++++++++++++++ slf4j ++++++++++++++++++++ --> <!-- slf4j --> <!-- 相关依赖(自动引入1.2.17):log4j- --> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> <version>${slf4j.version}</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>${slf4j.version}</version> </dependency> <!-- ++++++++++++++++++++++++++++++ commons-lang3 ++++++++++++++++++++ --> <!-- commons-lang3 --> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-lang3</artifactId> <version>${commons-lang3.version}</version> </dependency> <!-- ++++++++++++++++++++++++++++++ commons-text ++++++++++++++++++++ --> <!-- commons-text --> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-text</artifactId> <version>${commons-text.version}</version> </dependency> <!-- ++++++++++++++++++++++++++++++ springfox ++++++++++++++++++++ --> <!-- springfox --> <!-- 2018年6月23日 --> <!-- aopalliance-1.0.jar --> <!-- byte-buddy-1.8.12.jar --> <!-- classmate-1.4.0.jar --> <!-- guava-20.0.jar --> <!-- jackson-annotations-2.9.5.jar --> <!-- mapstruct-1.2.0.Final.jar --> <!-- slf4j-api-1.7.25.jar --> <!-- 版本4.0.9.RELEASE:spring-aop-、spring-beans-、spring-context-、spring-core-、spring-expression- --> <!-- 版本2.9.2:springfox-core-、springfox-schema-、springfox-spi-、springfox-spring-web-、springfox-swagger2- 、springfox-swagger-common- --> <!-- 版本1.2.0.RELEASE:spring-plugin-core-、spring-plugin-metadata- --> <!-- 版本1.5.20:swagger-annotations-、 swagger-models- --> <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger2</artifactId> <version>${springfox-swagger2.version}</version> </dependency> <!-- aopalliance-1.0.jar --> <!-- byte-buddy-1.8.12.jar --> <!-- guava-20.0.jar --> <!-- slf4j-api-1.7.25.jar --> <!-- 版本4.0.9.RELEASE:spring-aop-、spring-beans-、spring-context-、spring-core-、spring-expression- --> <!-- 版本2.9.2:springfox-core-、springfox-spi-、springfox-spring-web- --> <!-- 版本1.2.0.RELEASE:spring-plugin-core-、spring-plugin-metadata- --> <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger-ui</artifactId> <version>${springfox-swagger2.version}</version> </dependency> <!-- ++++++++++++++++++++++++++++++ jstl ++++++++++++++++++++ --> <!-- javax/servlet/jsp/jstl/core/Config --> <dependency> <groupId>javax.servlet</groupId> <artifactId>jstl</artifactId> <version>${jstl.version}</version> </dependency> <!-- ++++++++++++++++++++++++++++++ jetty-webapp ++++++++++++++++++++ --> <!-- --> <!-- javax.servlet-api-3.1.0.jar --> <!-- 版本9.4.12.v20180830:jetty-http-、jetty-io-、jetty-security-、jetty-server-、jetty-servlet-、jetty-util-、jetty-xml- --> <dependency> <groupId>org.eclipse.jetty</groupId> <artifactId>jetty-webapp</artifactId> <version>${jetty-webapp.version}</version> </dependency> <!-- ++++++++++++++++++++++++++++++ gson ++++++++++++++++++++ --> <!-- gson --> <dependency> <groupId>com.google.code.gson</groupId> <artifactId>gson</artifactId> <version>${gson.version}</version> </dependency> <!-- ++++++++++++++++++++++++++++++ json ++++++++++++++++++++ --> <dependency> <groupId>commons-beanutils</groupId> <artifactId>commons-beanutils</artifactId> <version>${commons-beanutils.version}</version> </dependency> <dependency> <groupId>commons-collections</groupId> <artifactId>commons-collections</artifactId> <version>${commons-collections.version}</version> </dependency> <dependency> <groupId>commons-logging</groupId> <artifactId>commons-logging</artifactId> <version>${commons-logging.version}</version> </dependency> <dependency> <groupId>net.sf.ezmorph</groupId> <artifactId>ezmorph</artifactId> <version>${ezmorph.version}</version> </dependency> <dependency> <groupId>net.sf.json-lib</groupId> <artifactId>json-lib</artifactId> <version>${json.version}</version> <classifier>jdk15</classifier> </dependency> <!-- ++++++++++++++++++++++++++++++ github验证码 ++++++++++++++++++++ --> <dependency> <groupId>com.github.bingoohuang</groupId> <artifactId>patchca</artifactId> <version>${patchca.version}</version> </dependency> <!-- <dependency> <groupId>net.pusuo</groupId> <artifactId>patchca</artifactId> <version>0.5.0</version> </dependency> --> <!-- ++++++++++++++++++++++++++++++ ++++++++++++++++++++ --> </dependencies> <build> <plugins> <!-- 配置Tomcat插件 --> <plugin> <groupId>org.apache.tomcat.maven</groupId> <artifactId>tomcat7-maven-plugin</artifactId> <configuration> <port>80</port> <path>/</path> <url>http://192.168.1.100:80/manager/text</url> <username>tomcat</username> <password>tomcat</password> </configuration> </plugin> <!-- 配置Tomcat插件 --> <!-- 默认 jdk 1.8 --> <plugin> <artifactId>maven-compiler-plugin</artifactId> <configuration> <source>1.8</source> <target>1.8</target> </configuration> </plugin> <!-- 默认 jdk 1.8 --> </plugins> </build> </project> 配置web.xml: <?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" id="WebApp_ID" version="4.0"> <display-name></display-name> <!-- 方便的Web应用程序的ApplicationContext实例化 --> <!-- 参见:https://docs.spring.io/spring/docs/5.0.8.RELEASE/spring-framework-reference/core.html#context-create --> <!-- 参见:https://docs.spring.io/spring/docs/current/spring-framework-reference/web.html#mvc-servlet --> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:spring-context.xml</param-value> </context-param> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <!-- 方便的Web应用程序的ApplicationContext实例化 --> <!-- DispatcherServlet --> <!-- 定义Spring MVC的前端控制器 --> <!-- 参见:https://docs.spring.io/spring/docs/current/spring-framework-reference/web.html#mvc-servlet --> <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:spring-mvc.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <!-- 让Spring MVC的前端控制器拦截所有请求 --> <servlet-mapping> <servlet-name>springmvc</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> <!-- 静态资源不拦截 --> <servlet-mapping> <servlet-name>default</servlet-name> <url-pattern>*.js</url-pattern> <url-pattern>*.css</url-pattern> <url-pattern>*.gif</url-pattern> <url-pattern>*.jpg</url-pattern> <url-pattern>*.png</url-pattern> <url-pattern>*.ico</url-pattern> <url-pattern>*.mp3</url-pattern> <url-pattern>*.woff</url-pattern> <url-pattern>*.json</url-pattern> </servlet-mapping> <!-- DispatcherServlet --> <!-- log4j2配置 --> <!-- 参见:http://logging.apache.org/log4j/2.x/manual/webapp.html --> <context-param> <param-name>log4jConfiguration</param-name> <param-value>classpath:log4j2.xml</param-value> </context-param> <listener> <listener-class>org.apache.logging.log4j.web.Log4jServletContextListener</listener-class> </listener> <filter> <filter-name>log4jServletFilter</filter-name> <filter-class>org.apache.logging.log4j.web.Log4jServletFilter</filter-class> </filter> <filter-mapping> <filter-name>log4jServletFilter</filter-name> <url-pattern>/*</url-pattern> <dispatcher>REQUEST</dispatcher> <dispatcher>FORWARD</dispatcher> <dispatcher>INCLUDE</dispatcher> <dispatcher>ERROR</dispatcher> <!-- <dispatcher>ASYNC</dispatcher> --> <!-- Servlet 3.0仅禁用自动初始化; 2.5不支持 --> </filter-mapping> <!-- github验证码 --> <!-- 直接访问http://127.0.0.1//validImg.jpg即可得到验证码,不受SSM控制 --> <servlet> <servlet-name>ValidCode</servlet-name> <servlet-class>net.csdn.servlet.ValidCode</servlet-class> </servlet> <servlet-mapping> <servlet-name>ValidCode</servlet-name> <url-pattern>/validImg.jpg</url-pattern> </servlet-mapping> <!-- 404页面 --> <!-- <error-page> <error-code>404</error-code> <location>/WEB-INF/error/404.html</location> </error-page> --> <!-- 500页面 --> <!-- <error-page> <error-code>500</error-code> <location>/WEB-INF/error/500.html</location> </error-page> --> <!-- <welcome-file-list> <welcome-file>index.html</welcome-file> <welcome-file>index.htm</welcome-file> <welcome-file>index.jsp</welcome-file> <welcome-file>default.html</welcome-file> <welcome-file>default.htm</welcome-file> <welcome-file>default.jsp</welcome-file> </welcome-file-list> --> </web-app> 配置jdbc.properties: # 在mysql-connector-java-8.0.12中已经被启用 com.mysql.jdbc.Driver # 在mysql-connector-java-8.0.12中使用 com.mysql.cj.jdbc.Driver # useSSL\=false 不验证SSL # serverTimezone\=GMT+8 设置时区为东8区 dataSource.driverClass=com.mysql.cj.jdbc.Driver dataSource.jdbcUrl=jdbc\:mysql\://127.0.0.1\:3306/csdn?useSSL\=false&serverTimezone\=GMT+8 dataSource.user=root dataSource.password=root dataSource.maxPoolSize=20 dataSource.maxIdleTime = 1000 dataSource.minPoolSize=5 dataSource.initialPoolSize=5 配置log4j.properties: log4j.rootLogger=info,stdout log4j.appender.stdout=org.apache.log4j.ConsoleAppender log4j.appender.stdout.layout=org.apache.log4j.PatternLayout log4j.appender.stdout.layout.ConversionPattern=[\u65F6\u95F4\:%d{yyyy-MM-dd hh\:mm\:ss}] [\u7EA7\u522B\:%p] [\u7C7B\:%c] [\u6D88\u606F\:%m] %n #log4j.logger.com.ibatis=debug #log4j.logger.com.ibatis.common.jdbc.SimpleDataSource=debug #log4j.logger.com.ibatis.common.jdbc.ScriptRunner=debug #log4j.logger.com.ibatis.sqlmap.engine.impl.SqlMapClientDelegate=debug #log4j.logger.java.sql.Connection=debug #log4j.logger.java.sql.Statement=debug #log4j.logger.java.sql.PreparedStatement=debug,stdout # Spring Stuff #log4j.logger.org.springframework=INFO #log4j.logger.org.springframework.oxm=INFO #log4j.logger.org.springframework.web=debug log4j.logger.net.csdn.aop.aspect.SystemLogAspect=debug 配置log4j2.xml: <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE xml> <Configuration status="OFF" monitorInterval="1800"> <properties> <!-- log打印到本地的路径 --> <property name="LOG_HOME">/log4j2/mybatis/genertor/logs/</property> <property name="ERROR_LOG_FILE_NAME">error</property> </properties> <Appenders> <!-- 控制台打印日志 --> <Console name="Console" target="SYSTEM_OUT"> <PatternLayout pattern="%d %-5p (%F:%L) - %m%n" /> </Console> <!-- 日志信息输出到文件配置 --> <RollingRandomAccessFile name="ErrorLog" fileName="${LOG_HOME}/${ERROR_LOG_FILE_NAME}.log" filePattern="${LOG_HOME}/${ERROR_LOG_FILE_NAME}.log.%d{yyyy-MM-dd}.log.gz"> <PatternLayout pattern="%d %-5p (%F:%L) - %m%n" /> <Policies> <!-- TimeBasedTriggeringPolicy指定的size是1,结合起来就是1天生成一个新文件。 --> <!-- 如果filePattern改成%d{yyyy-MM-dd HH}.gz,此时最小粒度为小时,则每一个小时生成一个文件。 --> <TimeBasedTriggeringPolicy /> <!-- 指定当文件体积大于size指定的值时,触发Rolling --> <SizeBasedTriggeringPolicy size="100 MB" /> </Policies> <!-- 指定最多保存的文件个数 --> <DefaultRolloverStrategy max="20" /> </RollingRandomAccessFile> </Appenders> <Loggers> <root level="info" includeLocation="true"> <appender-ref ref="ErrorLog" /> <appender-ref ref="Console" /> </root> </Loggers> </Configuration> 配置mybatis-config.xml: <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <!-- 使用log4j2打印查询语句 --> <settings> <!-- <setting name="logImpl" value="LOG4J2" /> --> <!-- 打印查询语句 --> <setting name="logImpl" value="STDOUT_LOGGING" /> </settings> <typeAliases> <package name="net.csdn" /> </typeAliases> <plugins> <!-- 拦截器配置 --> <plugin interceptor="net.csdn.util.sql.SqlCostInterceptor" /> </plugins> </configuration> 配置spring-context.xml: <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context" xmlns:mybatis="http://mybatis.org/schema/mybatis-spring" 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/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://mybatis.org/schema/mybatis-spring http://mybatis.org/schema/mybatis-spring.xsd"> <!-- mybatis:scan会将 net.csdn.mapper 包里的所有接口当作mapper配置,之后可以自动引入mapper接口 --> <!-- 多包用英文逗号隔开,如:<mybatis:scan base-package="net.csdn.mapper,com.baidu.mapper" /> --> <!-- 参见:http://www.mybatis.org/spring/mappers.html --> <mybatis:scan base-package="net.csdn.mapper" /> <!-- 自动检测类并注册bean定义 --> <!-- 参见:https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#beans-scanning-autodetection --> <!-- 多包用英文逗号隔开,如:<mybatis:scan base-package="net.csdn,com.baidu" /> --> <context:component-scan base-package="net.csdn" /> <!-- 使用BeanFactoryPostProcessor定制配置元数据 --> <!-- 参见:https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#beans-factory-extension-factory-postprocessors --> <context:property-override location="classpath:jdbc.properties" /> <!-- 配置c3p0数据源 --> <!-- 参见:https://www.mchange.com/projects/c3p0/ --> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" /> <!-- 配置SqlSessionFactory,org.mybatis.spring.SqlSessionFactoryBean是Mybatis社区开发用于整合Spring的bean --> <!-- 在基本的 MyBatis 中,session 工厂可以使用 SqlSessionFactoryBuilder 来创建。而在 MyBatis-Spring 中,则使用 SqlSessionFactoryBean 来替代。 --> <!-- 参见:http://www.mybatis.org/spring/zh/factorybean.html --> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="dataSource" ref="dataSource" /> <property name="mapperLocations"> <array> <!-- 扫描xml文件、可填写多个<value>值:如 <value>classpath:net/csdn/mapping/*.xml</value> <value>classpath:com/baidu/mapping/*.xml</value> --> <!-- value中不可有空格:org.apache.ibatis.binding.BindingException: Invalid bound statement (not found): --> <value>classpath:net/csdn/mapping/*.xml</value> </array> </property> <!-- 读取MyBatis配置文件的位置,SQL日志输出 --> <property name="configLocation" value="classpath:mybatis-config.xml" /> </bean> <!-- 声明性事务实现的示例 --> <!--参见: https://docs.spring.io/spring/docs/current/spring-framework-reference/data-access.html#transaction-declarative-first-example --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource" /> </bean> <!-- 启用支持annotation注解方式事务管理 --> <!-- 参见:https://docs.spring.io/spring/docs/current/spring-framework-reference/data-access.html#transaction-declarative-annotations --> <tx:annotation-driven transaction-manager="transactionManager" /> <!-- 扫描切点类组件 --> <context:component-scan base-package="net.csdn.aop.aspect" /> <!-- <context:component-scan base-package="net.csdn.service" /> --> <!-- 未知配置 --> <bean id="taskExecutor" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor"> <property name="corePoolSize" value="5" /> <property name="maxPoolSize" value="10" /> <!-- <property name="WaitForTasksToCompleteOnShutdown" value="true" /> --> </bean> <!-- bean定义 --> <!-- 参见:https://docs.spring.io/spring/docs/5.0.8.RELEASE/spring-framework-reference/core.html#beans-factory-instantiation --> </beans> 配置spring-mvc.xml: <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:websocket="http://www.springframework.org/schema/websocket" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/websocket http://www.springframework.org/schema/websocket/spring-websocket.xsd"> <!-- 自动扫描该包,SpringMVC会将包下用了@controller注解的类注册为Spring的controller --> <!-- 参见:https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#beans-stereotype-annotations --> <!-- 多个 controller 用英文逗号隔开,如:<context:component-scan base-package="net.csdn.controller,com.baidu.controller" /> --> <context:component-scan base-package="net.csdn.controller" /> <!-- 启用MVC注解 --> <!-- 参见:https://docs.spring.io/spring/docs/current/spring-framework-reference/web.html#mvc-config-enable --> <mvc:annotation-driven> <mvc:message-converters register-defaults="true"> <bean class="org.springframework.http.converter.StringHttpMessageConverter"> <property name="supportedMediaTypes"> <list> <!-- json乱码处理 --> <value>application/json; charset=UTF-8</value> </list> </property> </bean> </mvc:message-converters> </mvc:annotation-driven> <!-- 默认Servlet --> <!-- 使用默认的Servlet来响应静态文件 --> <!-- 参见:https://docs.spring.io/spring/docs/current/spring-framework-reference/web.html#mvc-default-servlet-handler --> <mvc:default-servlet-handler /> <!-- 查看解析器 --> <!-- 视图解析器 --> <!-- 参见:https://docs.spring.io/spring/docs/current/spring-framework-reference/web.html#mvc-view-jsp-resolver --> <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="viewClass" value="org.springframework.web.servlet.view.JstlView" /> <property name="prefix" value="/WEB-INF/content/" /> <!-- <property name="suffix" value=".jsp" /> --> </bean> <!-- 使用XML配置启用@AspectJ支持 --> <!-- 参见:https://docs.spring.io/spring/docs/5.0.8.RELEASE/spring-framework-reference/core.html#aop --> <aop:aspectj-autoproxy /> <!-- 参见:https://docs.spring.io/spring/docs/current/spring-framework-reference/web.html#websocket-server-handshake --> <!-- <websocket:handlers> <websocket:mapping path="/myHandler" handler="myHandler" /> <websocket:handshake-interceptors> <bean class="org.springframework.web.socket.server.support.HttpSessionHandshakeInterceptor" /> </websocket:handshake-interceptors> </websocket:handlers> <bean id="myHandler" class="net.csdn.websocket.MyHandler" /> --> <!-- 参见:https://docs.spring.io/spring/docs/current/spring-framework-reference/web.html#websocket-server-runtime-configuration --> <!-- 通过该类即可在普通工具类里获取spring管理的bean --> <bean class="net.csdn.spring.SpringTool" /> <!-- 配置拦截器 --> <mvc:interceptors> <!-- admin 拦截器 --> <mvc:interceptor> <!-- 拦截所有url --> <mvc:mapping path="/**" /> <!-- 不拦截url --> <mvc:exclude-mapping path="/index.html" /> <bean class="net.csdn.handlerInterceptor.HandlerInterceptor"></bean> </mvc:interceptor> </mvc:interceptors> </beans> 至此已配置完成。 SQL: /* Navicat Premium Data Transfer Source Server : 127.0.0.1 Source Server Type : MySQL Source Server Version : 50720 Source Host : 127.0.0.1:3306 Source Schema : csdn Target Server Type : MySQL Target Server Version : 50720 File Encoding : 65001 Date: 30/10/2018 15:34:47 */ SET NAMES utf8mb4; SET FOREIGN_KEY_CHECKS = 0; -- ---------------------------- -- Table structure for test_log -- ---------------------------- DROP TABLE IF EXISTS `test_log`; CREATE TABLE `test_log` ( `logId` int(11) NOT NULL AUTO_INCREMENT COMMENT '日志主键', `type` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '日志类型', `title` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '日志标题', `remoteAddr` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '请求地址', `requestUri` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT 'URI', `method` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '请求方式', `params` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '提交参数', `exception` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '异常', `operateDate` datetime(0) DEFAULT NULL COMMENT '开始时间', `timeout` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '结束时间', `userId` int(11) DEFAULT NULL COMMENT '用户ID', PRIMARY KEY (`logId`) USING BTREE ) ENGINE = InnoDB AUTO_INCREMENT = 7 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic; -- ---------------------------- -- Records of test_log -- ---------------------------- INSERT INTO `test_log` VALUES (1, 'info', '访问测试首页', '127.0.0.1', '//test/aop/index.do', 'GET', '', NULL, '2018-10-30 15:16:39', '0:0:0.20', NULL); INSERT INTO `test_log` VALUES (2, 'info', '访问测试登录', '127.0.0.1', '//test/aop/login.do', 'GET', 'username=xuxiaowei&password=', NULL, '2018-10-30 15:16:51', '0:0:0.71', 1); INSERT INTO `test_log` VALUES (3, 'info', '访问测试首页', '127.0.0.1', '//test/aop/index.do', 'GET', '', NULL, '2018-10-30 15:17:25', '0:0:0.0', 1); INSERT INTO `test_log` VALUES (4, 'info', '访问测试首页', '127.0.0.1', '//test/aop/index.do', 'GET', '', NULL, '2018-10-30 15:21:26', '0:0:0.27', NULL); INSERT INTO `test_log` VALUES (5, 'info', '访问测试登录', '127.0.0.1', '//test/aop/login.do', 'GET', 'username=xuxiaowei&password=', NULL, '2018-10-30 15:21:28', '0:0:0.69', 1); INSERT INTO `test_log` VALUES (6, 'error', '异常测试', '127.0.0.1', '//test/aop/err.do', 'GET', '', 'java.lang.ArithmeticException: / by zero', '2018-10-30 15:21:47', '0:0:0.0', 1); -- ---------------------------- -- Table structure for test_user -- ---------------------------- DROP TABLE IF EXISTS `test_user`; CREATE TABLE `test_user` ( `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '工号', `username` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '账号', `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '姓名', `password` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '密码', `sex` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '性别', `email` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '邮箱', `phone` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '手机', `locked` tinyint(4) DEFAULT NULL COMMENT '是否被锁定', `organizationId` int(11) DEFAULT NULL COMMENT '部门ID仅用户接受参数', `loginIp` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '最后登入IP', `loginDate` datetime(0) DEFAULT NULL COMMENT '最后登入日期', `photo` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '头像', `oldLoginIp` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '上次登入IP', `oldLoginDate` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '上次登入日期', `createBy` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '创建者ID', `updateBy` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '更新者ID', `createDate` datetime(0) DEFAULT NULL COMMENT '创建日期', `updateDate` datetime(0) DEFAULT NULL COMMENT '更新日期', PRIMARY KEY (`id`) USING BTREE ) ENGINE = InnoDB AUTO_INCREMENT = 2 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic; -- ---------------------------- -- Records of test_user -- ---------------------------- INSERT INTO `test_user` VALUES (1, 'xuxiaowei', NULL, '123456', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL); SET FOREIGN_KEY_CHECKS = 1; 测试日志: 相关类:以下类均为测试使用,可在上面的配置中删除。 net.csdn.aop.annotation.TestSystemControllerLog: 系统日志切片相关,自定义注解,拦截Controller,用于记操作日志: package net.csdn.aop.annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * 自定义注解 拦截Controller * * @author xuxiaowei * */ @Target({ ElementType.PARAMETER, ElementType.METHOD }) @Retention(RetentionPolicy.RUNTIME) public @interface TestSystemControllerLog { /** * 获取描述description * * @SystemControllerLog(description = "登入系统") * * @return */ String description() default ""; } net.csdn.aop.aspect.TestSystemLogAspect: 系统日志切点类: package net.csdn.aop.aspect; import java.lang.reflect.Method; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Map; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpSession; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.After; import org.aspectj.lang.annotation.AfterThrowing; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Pointcut; import org.aspectj.lang.reflect.MethodSignature; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.NamedThreadLocal; import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; import org.springframework.stereotype.Component; //import com.layui.test.entity.TestLog; //import com.layui.test.entity.TestUser; //import com.layui.test.service.TestLogService; //import com.layui.test.util.UuidUtils; import net.csdn.aop.annotation.TestSystemControllerLog; import net.csdn.entity.TestLog; import net.csdn.entity.TestUser; import net.csdn.service.TestLogService; import net.csdn.util.date.DateUtils; import net.csdn.util.string.StringUtils; /** * 系统日志切点类 * * @author xuxiaowei * */ @Aspect @Component public class TestSystemLogAspect { /** * */ private static final Logger logger = LoggerFactory.getLogger(TestSystemLogAspect.class); /** * 本地线程开始时间 */ private static final ThreadLocal<Date> beginTimeThreadLocal = new NamedThreadLocal<Date>("ThreadLocal beginTime"); /** * 本地线程日志 */ private static final ThreadLocal<TestLog> logThreadLocal = new NamedThreadLocal<TestLog>("ThreadLocal log"); /** * 当前用户 */ private static final ThreadLocal<TestUser> currentUser = new NamedThreadLocal<>("ThreadLocal user"); /** * 全局变量,同一个请求 */ @Autowired(required = false) private HttpServletRequest request; /** * 线程池任务执行程序 */ @Autowired private ThreadPoolTaskExecutor threadPoolTaskExecutor; /** * 日志储存service */ @Autowired private TestLogService logService; // /** // * Service层切点 // */ // @Pointcut("@annotation(cn.wimcn.test.annotation.SystemServiceLog)") // public void serviceAspect() { // System.out.println("+++++++++++++Service层切点+++++++++++++"); // } /** * Controller层切点 注解拦截 */ @Pointcut("@annotation(net.csdn.aop.annotation.TestSystemControllerLog)") public void testControllerAspect() { System.out.println("+++++++++++++Controller层切点 注解拦截+++++++++++++"); } /** * 方法规则拦截 */ @Pointcut("execution(* net.csdn.controller.*.*(..))") public void controllerPointerCut() { logger.debug("+++++++++++++方法规则拦截+++++++++++++"); } /** * 前置通知 用于拦截Controller层记录用户的操作的开始时间 * * @param joinPoint 切点 * @throws InterruptedException */ @Before("testControllerAspect()") public void doBefore(JoinPoint joinPoint) throws InterruptedException { Date beginTime = new Date(); // 设置本地线程开始时间 beginTimeThreadLocal.set(beginTime); // debug模式下 显式打印开始时间用于调试 // 在log4j中开启本类的debug if (logger.isDebugEnabled()) { logger.debug("开始计时: {} URI: {}", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").format(beginTime), request.getRequestURI()); } // 读取session中的用户 HttpSession session = request.getSession(); TestUser user = (TestUser) session.getAttribute("ims_user"); currentUser.set(user); } /** * 后置通知 用于拦截Controller层记录用户的操作 * * @param joinPoint 切点 */ @After("testControllerAspect()") public void doAfter(JoinPoint joinPoint) { TestUser user = currentUser.get(); // 登入login操作 前置通知时用户未校验 所以session中不存在用户信息 if (user == null) { HttpSession session = request.getSession(); user = (TestUser) session.getAttribute("ims_user"); if (user == null) { user = new TestUser(); } } Object[] args = joinPoint.getArgs(); System.out.println("joinPoint-args:" + args.toString()); String title = ""; String type = "info"; // 日志类型(info:入库,error:错误) String remoteAddr = request.getRemoteAddr();// 请求的IP String requestUri = request.getRequestURI();// 请求的Uri String method = request.getMethod(); // 请求的方法类型(post/get) Map<String, String[]> params = request.getParameterMap(); // 请求提交的参数 try { title = getControllerMethodDescription2(joinPoint); } catch (Exception e) { e.printStackTrace(); } // debu模式下打印JVM信息。 long beginTime = beginTimeThreadLocal.get().getTime();// 得到线程绑定的局部变量(开始时间) long endTime = System.currentTimeMillis(); // 2、结束时间 if (logger.isDebugEnabled()) { logger.debug("计时结束:{} URI: {} 耗时: {} 最大内存: {}m 已分配内存: {}m 已分配内存中的剩余空间: {}m 最大可用内存: {}m", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").format(endTime), request.getRequestURI(), DateUtils.formatDateTime(endTime - beginTime), Runtime.getRuntime().maxMemory() / 1024 / 1024, Runtime.getRuntime().totalMemory() / 1024 / 1024, Runtime.getRuntime().freeMemory() / 1024 / 1024, (Runtime.getRuntime().maxMemory() - Runtime.getRuntime().totalMemory() + Runtime.getRuntime().freeMemory()) / 1024 / 1024); } TestLog testLog = new TestLog(); // testLog.setLogid(UuidUtils.creatUUID()); testLog.setTitle(title); testLog.setType(type); testLog.setRemoteAddr(remoteAddr); testLog.setRequestUri(requestUri); testLog.setMethod(method); testLog.setParams(StringUtils.getMapToParams(params)); // testLog.setUserid(user.getId()); testLog.setUserId(user.getId()); Date operateDate = beginTimeThreadLocal.get(); testLog.setOperateDate(operateDate); testLog.setTimeout(DateUtils.formatDateTime(endTime - beginTime)); // 1.直接执行保存操作 // this.logService.createSystemLog(log); // 2.优化:异步保存日志 // new SaveLogThread(log, logService).start(); // 3.再优化:通过线程池来执行日志保存 threadPoolTaskExecutor.execute(new SaveLogThread(testLog, logService)); logThreadLocal.set(testLog); } /** * 异常通知 * * @param joinPoint * @param e */ @AfterThrowing(pointcut = "testControllerAspect()", throwing = "e") public void doAfterThrowing(JoinPoint joinPoint, Throwable e) { TestLog testLog = logThreadLocal.get(); if (testLog != null) { testLog.setType("error"); testLog.setException(e.toString()); new UpdateLogThread(testLog, logService).start(); } } /** * 获取注解中对方法的描述信息 用于Controller层注解 * * @param joinPoint 切点 * @return 方法描述 */ public static String getControllerMethodDescription2(JoinPoint joinPoint) { /** * Returns the signature at the join point. 返回连接点处的签名。 * getStaticPart().getSignature() returns the same object 返回相同的对象 */ MethodSignature signature = (MethodSignature) joinPoint.getSignature(); Method method = signature.getMethod(); TestSystemControllerLog controllerLog = method.getAnnotation(TestSystemControllerLog.class); String discription = controllerLog.description(); return discription; } /** * 保存日志线程 * * @author xuxiaowei * */ private static class SaveLogThread implements Runnable { private TestLog testLog; private TestLogService testLogService; public SaveLogThread(TestLog testLog, TestLogService testLogService) { this.testLog = testLog; this.testLogService = testLogService; } @Override public void run() { testLogService.insert(testLog); } } /** * 日志更新线程 * * @author xuxiaowei * */ private static class UpdateLogThread extends Thread { private TestLog testLog; private TestLogService logService; public UpdateLogThread(TestLog testLog, TestLogService logService) { super(UpdateLogThread.class.getSimpleName()); this.testLog = testLog; this.logService = logService; } @Override public void run() { this.logService.updateByPrimaryKeySelective(testLog); } } } net.csdn.controller.TestAopController: 测试Controller: package net.csdn.controller; import java.util.List; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.RequestMapping; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import net.csdn.aop.annotation.TestSystemControllerLog; import net.csdn.entity.TestUser; import net.csdn.entity.TestUserExample; import net.csdn.entity.TestUserExample.Criteria; import net.csdn.service.TestUserService; /** * 测试AOP * * @author xuxiaowei * */ @Api(value = "/test", tags = "系统登入接口") @Controller @RequestMapping("/test/aop") public class TestAopController { private static final Logger logger = LoggerFactory.getLogger(TestAopController.class); @Autowired private TestUserService testUserService; /** * 测试主页 * * @param request * @param response * @return */ @TestSystemControllerLog(description = "访问测试首页") @RequestMapping("/index.do") public String test(HttpServletRequest request, HttpServletResponse response) { System.out.println("/index.do"); logger.info("{} 访问测试首页", "xxx"); return "test/aop/index.jsp"; } /** * 测试登录方法 * * @param request * @param response * @param test * @param model * @return */ @ApiOperation(value = "登入系统", notes = "登入系统", httpMethod = "POST") @TestSystemControllerLog(description = "访问测试登录") @RequestMapping("/login.do") public String login(HttpServletRequest request, HttpServletResponse response, TestUser testUser, Model model) { System.out.println("/login.do"); String username2 = testUser.getUsername(); String password2 = testUser.getPassword(); System.out.println(username2); System.out.println(password2); TestUserExample testUserExample = new TestUserExample(); Criteria createCriteria = testUserExample.createCriteria(); createCriteria.andUsernameEqualTo(username2); createCriteria.andPasswordEqualTo(password2); List<TestUser> testUsers = testUserService.selectByExample(testUserExample); HttpSession session = request.getSession(); if (testUsers.size() > 0) { logger.info("{} 登入系统成功!", username2); String string = testUsers.toString(); System.out.println(string); model.addAttribute("string", string); session.setAttribute("ims_user", testUsers.get(0)); } else { logger.info("{} 登入系统失败!", username2); } return "test/aop/main.jsp"; } @TestSystemControllerLog(description = "异常测试") @RequestMapping("/err.do") public String err(HttpServletRequest request, HttpServletResponse response) { System.out.println("/err.do"); logger.info("{} 访问页面异常测试", "xxx"); int i = 5 / 0; System.out.println(i); return "test/aop/index.jsp"; } } net.csdn.handlerInterceptor.HandlerInterceptor: 拦截器: package net.csdn.handlerInterceptor; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.ModelAndView; /** * * @author xuxiaowei * */ public class HandlerInterceptor implements HandlerInterceptor { @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { // TODO Auto-generated method stub HandlerInterceptor.super.postHandle(request, response, handler, modelAndView); } @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { // TODO Auto-generated method stub return HandlerInterceptor.super.preHandle(request, response, handler); } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { // TODO Auto-generated method stub HandlerInterceptor.super.afterCompletion(request, response, handler, ex); } } 实体类相关,自动生成: 工具类:用于生成entity、mapper、mapping、service、serviceImpl: net.csdn.servlet.ValidCode: 验证码生成器: package net.csdn.servlet; import java.awt.Color; import java.io.IOException; import java.util.Random; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import com.github.bingoohuang.patchca.color.ColorFactory; import com.github.bingoohuang.patchca.custom.ConfigurableCaptchaService; import com.github.bingoohuang.patchca.filter.predefined.CurvesRippleFilterFactory; import com.github.bingoohuang.patchca.filter.predefined.DiffuseRippleFilterFactory; import com.github.bingoohuang.patchca.filter.predefined.DoubleRippleFilterFactory; import com.github.bingoohuang.patchca.filter.predefined.MarbleRippleFilterFactory; import com.github.bingoohuang.patchca.filter.predefined.WobbleRippleFilterFactory; import com.github.bingoohuang.patchca.font.RandomFontFactory; import com.github.bingoohuang.patchca.utils.encoder.EncoderHelper; import com.github.bingoohuang.patchca.word.RandomWordFactory; /** * github验证码 * * @author xuxiaowei * */ public class ValidCode extends HttpServlet { /** * */ private static final long serialVersionUID = 1L; private static ConfigurableCaptchaService cs = new ConfigurableCaptchaService(); private static Random random = new Random(); static { // cs.setColorFactory(new SingleColorFactory(new Color(25, 60, 170))); cs.setColorFactory(new ColorFactory() { @Override public Color getColor(int x) { int[] c = new int[3]; int i = random.nextInt(c.length); for (int fi = 0; fi < c.length; fi++) { if (fi == i) { c[fi] = random.nextInt(71); } else { c[fi] = random.nextInt(256); } } return new Color(c[0], c[1], c[2]); } }); RandomWordFactory randomWordFactory = new RandomWordFactory(); // 字符范围 randomWordFactory.setCharacters("23456789abcdefghijkmnpqrstuvwxyzABCDEFGHIJKLMNPQRSTUVWXYZ"); // 字符数量范围 randomWordFactory.setMaxLength(5); randomWordFactory.setMinLength(3); cs.setWordFactory(randomWordFactory); // 图片像素 cs.setHeight(40); cs.setWidth(130); // 字体大小范围 RandomFontFactory randomFontFactory = new RandomFontFactory(); randomFontFactory.setMaxSize(40); randomFontFactory.setMinSize(30); cs.setFontFactory(randomFontFactory); } @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { switch (random.nextInt(5)) { case 0: cs.setFilterFactory(new CurvesRippleFilterFactory(cs.getColorFactory())); break; case 1: cs.setFilterFactory(new MarbleRippleFilterFactory()); break; case 2: cs.setFilterFactory(new DoubleRippleFilterFactory()); break; case 3: cs.setFilterFactory(new WobbleRippleFilterFactory()); break; case 4: cs.setFilterFactory(new DiffuseRippleFilterFactory()); break; } HttpSession session = request.getSession(); session = request.getSession(); setResponseHeaders(response); String token = EncoderHelper.getChallangeAndWriteImage(cs, "png", response.getOutputStream()); session.setAttribute("verifyCode", token); } protected void setResponseHeaders(HttpServletResponse response) { response.setContentType("image/png"); response.setHeader("Cache-Control", "no-cache, no-store"); response.setHeader("Pragma", "no-cache"); long time = System.currentTimeMillis(); response.setDateHeader("Last-Modified", time); response.setDateHeader("Date", time); response.setDateHeader("Expires", time); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // TODO Auto-generated method stub super.doPost(req, resp); } } net.csdn.spring.SpringTool: 通过该类即可在普通工具类里获取spring管理的bean: package net.csdn.spring; import org.springframework.beans.BeansException; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; /** * 通过该类即可在普通工具类里获取spring管理的bean * * @author xuxiaowei * */ public final class SpringTool implements ApplicationContextAware { private static ApplicationContext applicationContext = null; @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { if (SpringTool.applicationContext == null) { SpringTool.applicationContext = applicationContext; System.out.println(); System.out.println("========" + "ApplicationContext配置成功," + "在普通类可以通过调用ToolSpring.getAppContext()获取applicationContext对象," + "applicationContext=" + applicationContext + "========"); System.out.println(); } } /** * * @return */ public static ApplicationContext getApplicationContext() { return applicationContext; } /** * 获取been * * @param serviceName * @return */ public static Object getBean(String serviceName) { return getApplicationContext().getBean(serviceName); } } net.csdn.util.sql.SqlCostInterceptor: Sql执行时间记录拦截器: package net.csdn.util.sql; import java.sql.Statement; import java.util.Properties; import org.apache.ibatis.executor.statement.StatementHandler; import org.apache.ibatis.plugin.Interceptor; import org.apache.ibatis.plugin.Intercepts; import org.apache.ibatis.plugin.Invocation; import org.apache.ibatis.plugin.Plugin; import org.apache.ibatis.plugin.Signature; import org.apache.ibatis.session.ResultHandler; /** * Sql执行时间记录拦截器 * * @author xuxiaowei * */ @Intercepts({ @Signature(type = StatementHandler.class, method = "query", args = { Statement.class, ResultHandler.class }), @Signature(type = StatementHandler.class, method = "update", args = { Statement.class }), @Signature(type = StatementHandler.class, method = "batch", args = { Statement.class }) }) public class SqlCostInterceptor implements Interceptor { @Override public Object intercept(Invocation invocation) throws Throwable { long startTime = System.currentTimeMillis(); try { return invocation.proceed(); } finally { long endTime = System.currentTimeMillis(); long sqlCost = endTime - startTime; System.out.println("执行SQL耗时 : [" + sqlCost + "ms ] "); } } @Override public Object plugin(Object target) { return Plugin.wrap(target, this); } @Override public void setProperties(Properties properties) { } } net.csdn.util.string.StringUtils: 字符串工具类: package net.csdn.util.string; import java.io.UnsupportedEncodingException; import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.servlet.http.HttpServletRequest; //deprecated as of 3.6, use commons-text //从3.6开始弃用,使用commons-text //import org.apache.commons.lang3.StringEscapeUtils; //commons-text-1.4.jar import org.apache.commons.text.StringEscapeUtils; /** * 字符串工具类 * * 继承org.apache.commons.lang3.StringUtils类 * * @author xuxiaowei * */ public class StringUtils extends org.apache.commons.lang3.StringUtils { private static final char SEPARATOR = '_'; private static final String CHARSET_NAME = "UTF-8"; /** * 首字母小写 * * @param string * @return */ public static String lowerFirst(String string) { char[] cs = string.toCharArray(); cs[0] += 32; String valueOf = String.valueOf(cs); return valueOf; } /** * 转换为字节数组 * * @param str * @return */ public static byte[] getBytes(String str) { if (str != null) { try { return str.getBytes(CHARSET_NAME); } catch (UnsupportedEncodingException e) { return null; } } else { return null; } } /** * 转换为字节数组 * * @param str * @return */ public static String toString(byte[] bytes) { try { return new String(bytes, CHARSET_NAME); } catch (UnsupportedEncodingException e) { return EMPTY; } } /** * 是否包含字符串 * * @param str 验证字符串 * @param strs 字符串组 * @return 包含返回true */ public static boolean inString(String str, String... strs) { if (str != null) { for (String s : strs) { if (str.equals(trim(s))) { return true; } } } return false; } /** * 替换掉HTML标签方法 * * @param html * @return */ public static String replaceHtml(String html) { if (isBlank(html)) { return ""; } String regEx = "<.+?>"; Pattern p = Pattern.compile(regEx); Matcher m = p.matcher(html); String s = m.replaceAll(""); return s; } /** * 替换为手机识别的HTML,去掉样式及属性,保留回车。 * * @param html * @return */ public static String replaceMobileHtml(String html) { if (html == null) { return ""; } return html.replaceAll("<([a-z]+?)\\s+?.*?>", "<$1>"); } // /** // * 替换为手机识别的HTML,去掉样式及属性,保留回车。 // * // * @param txt // * @return // */ // public static String toHtml(String txt) { // if (txt == null) { // return ""; // } // return replace(replace(Encodes.escapeHtml(txt), "\n", "<br/>"), "\t", " "); // } /** * 缩略字符串(不区分中英文字符) * * @param str 目标字符串 * @param length 截取长度 * @return */ public static String abbr(String str, int length) { if (str == null) { return ""; } try { StringBuilder sb = new StringBuilder(); int currentLength = 0; for (char c : replaceHtml(StringEscapeUtils.unescapeHtml4(str)).toCharArray()) { currentLength += String.valueOf(c).getBytes("GBK").length; if (currentLength <= length - 3) { sb.append(c); } else { sb.append("..."); break; } } return sb.toString(); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } return ""; } /** * 转换为Double类型 * * @param val * @return */ public static Double toDouble(Object val) { if (val == null) { return 0D; } try { return Double.valueOf(trim(val.toString())); } catch (Exception e) { return 0D; } } /** * 转换为Float类型 * * @param val * @return */ public static Float toFloat(Object val) { return toDouble(val).floatValue(); } /** * 转换为Long类型 * * @param val * @return */ public static Long toLong(Object val) { return toDouble(val).longValue(); } /** * 转换为Integer类型 * * @param val * @return */ public static Integer toInteger(Object val) { return toLong(val).intValue(); } // /** // * 获得i18n字符串 // * // * @param code // * @param args // * @return // */ // public static String getMessage(String code, Object[] args) { // LocaleResolver localLocaleResolver = (LocaleResolver) SpringContextHolder.getBean(LocaleResolver.class); // HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()) // .getRequest(); // Locale localLocale = localLocaleResolver.resolveLocale(request); // return SpringContextHolder.getApplicationContext().getMessage(code, args, localLocale); // } /** * 获得用户远程地址 * * @param request * @return */ public static String getRemoteAddr(HttpServletRequest request) { String remoteAddr = request.getHeader("X-Real-IP"); if (isNotBlank(remoteAddr)) { remoteAddr = request.getHeader("X-Forwarded-For"); } else if (isNotBlank(remoteAddr)) { remoteAddr = request.getHeader("Proxy-Client-IP"); } else if (isNotBlank(remoteAddr)) { remoteAddr = request.getHeader("WL-Proxy-Client-IP"); } return remoteAddr != null ? remoteAddr : request.getRemoteAddr(); } /** * 驼峰命名法工具 * * toCamelCase("hello_world") == "helloWorld" * toCapitalizeCamelCase("hello_world") == "HelloWorld" * toUnderScoreCase("helloWorld") = "hello_world" * * @param s * @return */ public static String toCamelCase(String s) { if (s == null) { return null; } s = s.toLowerCase(); StringBuilder sb = new StringBuilder(s.length()); boolean upperCase = false; for (int i = 0; i < s.length(); i++) { char c = s.charAt(i); if (c == SEPARATOR) { upperCase = true; } else if (upperCase) { sb.append(Character.toUpperCase(c)); upperCase = false; } else { sb.append(c); } } return sb.toString(); } /** * 驼峰命名法工具 * * toCamelCase("hello_world") == "helloWorld" * toCapitalizeCamelCase("hello_world") == "HelloWorld" * toUnderScoreCase("helloWorld") = "hello_world" * * @param s * @return */ public static String toCapitalizeCamelCase(String s) { if (s == null) { return null; } s = toCamelCase(s); return s.substring(0, 1).toUpperCase() + s.substring(1); } /** * 驼峰命名法工具 * * toCamelCase("hello_world") == "helloWorld" * toCapitalizeCamelCase("hello_world") == "HelloWorld" * toUnderScoreCase("helloWorld") = "hello_world" * * @param s * @return */ public static String toUnderScoreCase(String s) { if (s == null) { return null; } StringBuilder sb = new StringBuilder(); boolean upperCase = false; for (int i = 0; i < s.length(); i++) { char c = s.charAt(i); boolean nextUpperCase = true; if (i < (s.length() - 1)) { nextUpperCase = Character.isUpperCase(s.charAt(i + 1)); } if ((i > 0) && Character.isUpperCase(c)) { if (!upperCase || !nextUpperCase) { sb.append(SEPARATOR); } upperCase = true; } else { upperCase = false; } sb.append(Character.toLowerCase(c)); } return sb.toString(); } /** * 驼峰转下划线 (暂不建议使用toUnderScoreCase) * * @param camelCaseName * @return */ public static String toUnderscoreName(String camelCaseName) { StringBuilder result = new StringBuilder(); if (camelCaseName != null && camelCaseName.length() > 0) { result.append(camelCaseName.substring(0, 1).toLowerCase()); for (int i = 1; i < camelCaseName.length(); i++) { char ch = camelCaseName.charAt(i); if (Character.isUpperCase(ch)) { result.append("_"); result.append(Character.toLowerCase(ch)); } else { result.append(ch); } } } return result.toString(); } /** * 如果不为空,则设置值 * * @param target * @param source */ public static void setValueIfNotBlank(String target, String source) { if (isNotBlank(source)) { target = source; } } /** * 转换为JS获取对象值,生成三目运算返回结果 * * 例如:row.user.id * * 返回:!row?'':!row.user?'':!row.user.id?'':row.user.id * * @param objectString 对象串 */ public static String jsGetVal(String objectString) { StringBuilder result = new StringBuilder(); StringBuilder val = new StringBuilder(); String[] vals = split(objectString, "."); for (int i = 0; i < vals.length; i++) { val.append("." + vals[i]); result.append("!" + (val.substring(1)) + "?'':"); } result.append(val.substring(1)); return result.toString(); } /** * 转换为utf-8字符串 * * @param s * @return */ public static String toUtf8String(String s) { StringBuffer sb = new StringBuffer(); for (int i = 0; i < s.length(); i++) { char c = s.charAt(i); if (c >= 0 && c <= 255) { sb.append(c); } else { byte[] b; try { b = Character.toString(c).getBytes("utf-8"); } catch (Exception ex) { b = new byte[0]; } for (int j = 0; j < b.length; j++) { int k = b[j]; if (k < 0) k += 256; sb.append("%" + Integer.toHexString(k).toUpperCase()); } } } return sb.toString(); } /** * * Map<String, String[]> 转 String * * @param paramMap * @return */ public static String getMapToParams(Map<String, String[]> paramMap) { if (paramMap == null) { return ""; } StringBuilder params = new StringBuilder(); for (Map.Entry<String, String[]> param : ((Map<String, String[]>) paramMap).entrySet()) { params.append(("".equals(params.toString()) ? "" : "&") + param.getKey() + "="); String paramValue = (param.getValue() != null && param.getValue().length > 0 ? param.getValue()[0] : ""); params.append(StringUtils.abbr(StringUtils.endsWithIgnoreCase(param.getKey(), "password") ? "" : paramValue, 100)); } return params.toString(); } } net.csdn.util.date.DateUtils: 日期工具类: package net.csdn.util.date; import java.text.ParseException; import java.util.Date; import org.apache.commons.lang3.time.DateFormatUtils; /** * 日期工具类 * * 继承org.apache.commons.lang3.time.DateUtils类 * * @author xuxiaowei * */ public class DateUtils extends org.apache.commons.lang3.time.DateUtils { private static String[] parsePatterns = { "yyyy-MM-dd HH:mm:ss", "yyyy/MM/dd HH:mm:ss", "yyyy.MM.dd HH:mm:ss", "yyyy-MM-dd HH:mm", "yyyy/MM/dd HH:mm", "yyyy.MM.dd HH:mm", "yyyy-MM-dd", "yyyy/MM/dd", "yyyy.MM.dd", "yyyy-MM", "yyyy/MM", "yyyy.MM" }; /** * 得到当前日期字符串 格式(yyyy-MM-dd) * * @return */ public static String getDate() { return getDate("yyyy-MM-dd"); } /** * 得到当前日期字符串 格式(yyyy-MM-dd) pattern可以为:"yyyy-MM-dd" "HH:mm:ss" "E" * * @param pattern * @return */ public static String getDate(String pattern) { return DateFormatUtils.format(new Date(), pattern); } /** * 得到日期字符串 默认格式(yyyy-MM-dd) pattern可以为:"yyyy-MM-dd" "HH:mm:ss" "E" * * @param date * @param pattern * @return */ public static String formatDate(Date date, Object... pattern) { String formatDate = null; if (pattern != null && pattern.length > 0) { formatDate = DateFormatUtils.format(date, pattern[0].toString()); } else { formatDate = DateFormatUtils.format(date, "yyyy-MM-dd"); } return formatDate; } /** * 得到日期时间字符串,转换格式(yyyy-MM-dd HH:mm:ss) * * @param date * @return */ public static String formatDateTime(Date date) { return formatDate(date, "yyyy-MM-dd HH:mm:ss"); } /** * 得到当前时间字符串 格式(HH:mm:ss) * * @return */ public static String getTime() { return formatDate(new Date(), "HH:mm:ss"); } /** * 得到当前日期和时间字符串 格式(yyyy-MM-dd HH:mm:ss) * * @return */ public static String getDateTime() { return formatDate(new Date(), "yyyy-MM-dd HH:mm:ss"); } /** * 得到当前年份字符串 格式(yyyy) * * @return */ public static String getYear() { return formatDate(new Date(), "yyyy"); } /** * 得到当前月份字符串 格式(MM) * * @return */ public static String getMonth() { return formatDate(new Date(), "MM"); } /** * 得到当天字符串 格式(dd) * * @return */ public static String getDay() { return formatDate(new Date(), "dd"); } /** * 得到当前星期字符串 格式(E)星期几 * * @return */ public static String getWeek() { return formatDate(new Date(), "E"); } /** * 日期型字符串转化为日期格式 * * "yyyy-MM-dd HH:mm:ss", "yyyy/MM/dd HH:mm:ss", "yyyy.MM.dd HH:mm:ss", * "yyyy-MM-dd HH:mm", "yyyy/MM/dd HH:mm", "yyyy.MM.dd HH:mm", "yyyy-MM-dd", * "yyyy/MM/dd", "yyyy.MM.dd", "yyyy-MM", "yyyy/MM", "yyyy.MM" * * @param str * @return */ public static Date parseDate(Object str) { if (str == null) { return null; } try { return parseDate(str.toString(), parsePatterns); } catch (ParseException e) { return null; } } /** * 获取过去的天数 * * @param date * @return */ public static long pastDays(Date date) { long t = new Date().getTime() - date.getTime(); return t / (24 * 60 * 60 * 1000); } /** * 获取过去的小时 * * @param date * @return */ public static long pastHour(Date date) { long t = new Date().getTime() - date.getTime(); return t / (60 * 60 * 1000); } /** * 获取过去的分钟 * * @param date * @return */ public static long pastMinutes(Date date) { long t = new Date().getTime() - date.getTime(); return t / (60 * 1000); } /** * 转换为时间(天,时:分:秒.毫秒) * * @param timeMillis * @return */ public static String formatDateTime(long timeMillis) { long day = timeMillis / (24 * 60 * 60 * 1000); long hour = (timeMillis / (60 * 60 * 1000) - day * 24); long min = ((timeMillis / (60 * 1000)) - day * 24 * 60 - hour * 60); long s = (timeMillis / 1000 - day * 24 * 60 * 60 - hour * 60 * 60 - min * 60); long sss = (timeMillis - day * 24 * 60 * 60 * 1000 - hour * 60 * 60 * 1000 - min * 60 * 1000 - s * 1000); return (day > 0 ? day + "," : "") + hour + ":" + min + ":" + s + "." + sss; } /** * 获取两个日期之间的天数 * * @param before * @param after * @return */ public static double getDistanceOfTwoDate(Date before, Date after) { long beforeTime = before.getTime(); long afterTime = after.getTime(); return (afterTime - beforeTime) / (1000 * 60 * 60 * 24); } /** * @param args * @throws ParseException */ public static void main(String[] args) throws ParseException { // System.out.println(formatDate(parseDate("2010/3/6"))); // System.out.println(getDate("yyyy年MM月dd日 E")); // long time = new Date().getTime()-parseDate("2012-11-19").getTime(); // System.out.println(time/(24*60*60*1000)); } } 项目源码:Spring 5 + Spring MVC 5 + MyBatis 3 的 Maven 项目集成 源码 本文参考: Spring AOP实现后台管理系统日志管理相关链接:
MyEclipse CI 2018.9.0 配置 Apache Maven 3.5.4
在MyEclipse CI 2018.9.0 中使用 Maven 3.5.4 创建Maven项目
在MyEclipse中使用SVN提交(自动忽略 .settings .project .classpath等)、检出(无.settings .project .classpath文件等)Maven代码