SSM/springBoot代码生成器——新增全局事务切面,logback日志支持,SSM框架支持

目录

 

小记

新增全局事务

logback日志支持

SSM框架支持

运行效果


小记

这两天比较清闲,对生成器做了进一步的优化与更新,一起来看一下吧!

新增全局事务

相信我们都知道事务在数据操作的过程当中十分重要,举个最简单的例子,如果程序正在处理添加数据的业务,但是程序执行完sql之后的业务流程中产生了异常,这个时候应该回滚,则添加数据无效,保证了业务的统一和数据的完整。一般情况下,使用mysql的时候都是默认使用的innoDB数据库引擎,与MYISAM最大的区别就是加入了事务的支持,我们在平时的开发过程中最常用的也是InnoDB,所以本次更新特地增加了全局的事务支持

先说springboot,增加了transactionAdviceConfig.ftl模板文件,代码如下:

package ${packageName}.config;

import org.aspectj.lang.annotation.Aspect;
import org.springframework.aop.Advisor;
import org.springframework.aop.aspectj.AspectJExpressionPointcut;
import org.springframework.aop.support.DefaultPointcutAdvisor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.interceptor.DefaultTransactionAttribute;
import org.springframework.transaction.interceptor.NameMatchTransactionAttributeSource;
import org.springframework.transaction.interceptor.TransactionInterceptor;

/**
 * 全局事务支持
 * 
 * @author zrx
 *
 */
@Aspect
@Configuration
public class TransactionAdviceConfig {
	
	private static final String AOP_POINTCUT_EXPRESSION = "execution(* ${packageName}.service.impl.*.*(..))";

	@Autowired
	private PlatformTransactionManager transactionManager;

	@Bean
	public TransactionInterceptor txAdvice() {

		DefaultTransactionAttribute txAttr_REQUIRED = new DefaultTransactionAttribute();
		txAttr_REQUIRED.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);

		DefaultTransactionAttribute txAttr_REQUIRED_READONLY = new DefaultTransactionAttribute();
		txAttr_REQUIRED_READONLY.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
		txAttr_REQUIRED_READONLY.setReadOnly(true);

		NameMatchTransactionAttributeSource source = new NameMatchTransactionAttributeSource();
		source.addTransactionalMethod("add*", txAttr_REQUIRED);
		source.addTransactionalMethod("delete*", txAttr_REQUIRED);
		source.addTransactionalMethod("update*", txAttr_REQUIRED);
		source.addTransactionalMethod("select*", txAttr_REQUIRED_READONLY);
		source.addTransactionalMethod("likeSelect*", txAttr_REQUIRED_READONLY);
		return new TransactionInterceptor(transactionManager, source);
	}

	@Bean
	public Advisor txAdviceAdvisor() {
		AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
		pointcut.setExpression(AOP_POINTCUT_EXPRESSION);
		return new DefaultPointcutAdvisor(pointcut, txAdvice());
	}
}

很简单易懂的事务切面,AOP_POINTCUT_EXPRESSION为定义的切入点表达式,这里的${packageName}由freemarker引擎渲染,从而得到正确的属性,生成相应的代码。在这里我把增删改方法的事务传播行为设置为了required,同样也是最常用的,查询方法设置为了readonly,关于事务的传播行为,不明白的朋友可以自行百度,这在平时的开发中还是很重要的一个概念,同样事务的隔离级别也同样需要了解,隔离级别一般设置为read commit(读已提交)即可,当然如果是在高并发的系统中就要考虑数据的一致性和准确性。

举个最简单的例子,用户a在执行a事务,在a表中查询出了一条记录,假设这条记录的某个字段名称也为a,然后继续执行事务。。这个时候b用户去a表中把这条记录的名称更新为b然后提交,但此时a用户的事务还没有结束,后面使用到a表相关的查询,发现字段名称已经不是a而是b了,这就造成了可重复读。解决此类问题的方法也很多,如修改隔离级别,程序加锁等,具体情况需要具体分析。

回到正题,ssm方面增加了mvc-jdbcProperties.ftl,mvc-spring-mvc.ftl,mvc-spring-mybatis.ftl,mvcInterceptor.ftl三个主要模板,事务的相关配置在mvc-spring-mybatis.ftl当中,代码如下:

<?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:jee="http://www.springframework.org/schema/jee"
	xmlns:lang="http://www.springframework.org/schema/lang"
	xmlns:util="http://www.springframework.org/schema/util"
	xmlns:tx="http://www.springframework.org/schema/tx"
	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/aop
							http://www.springframework.org/schema/aop/spring-aop.xsd  
							http://www.springframework.org/schema/jee 
							http://www.springframework.org/schema/jee/spring-jee.xsd 
							http://www.springframework.org/schema/lang 
							http://www.springframework.org/schema/lang/spring-lang.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://www.springframework.org/schema/util 
							http://www.springframework.org/schema/util/spring-util.xsd 
							http://www.springframework.org/schema/mvc 
							http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd">
	<!-- 引入配置文件 -->
	<context:annotation-config />
	<context:component-scan base-package="${packageName}.*" />

	<!-- 加载连接数据库的参数配置文件 -->
	<bean
		class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
		<property name="locations">
			<list>
				<value>classpath:jdbc.properties</value>
				<!-- <value>classpath:redis.properties</value> -->
			</list>
		</property>
		<property name="ignoreUnresolvablePlaceholders" value="true" />
	</bean>

	<!-- 阿里 druid 数据库连接池 -->
	<bean id="dataSource"
		class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close">
		<!-- 数据库基本信息配置 -->
		<property name="driverClassName" value="<#noparse>${</#noparse>jdbc.driver}" />
		<property name="url" value="<#noparse>${</#noparse>jdbc.url}" />
		<property name="username" value="<#noparse>${</#noparse>jdbc.username}" />
		<property name="password" value="<#noparse>${</#noparse>jdbc.password}" />

		<property name="filters" value="<#noparse>${</#noparse>jdbc.filters}" />

		<!-- 最大并发连接数 -->
		<property name="maxActive" value="<#noparse>${</#noparse>jdbc.maxActive}" />

		<!-- 初始化连接数量 -->
		<property name="initialSize" value="<#noparse>${</#noparse>jdbc.initialSize}" />

		<!-- 配置获取连接等待超时的时间 -->
		<property name="maxWait" value="<#noparse>${</#noparse>jdbc.maxWait}" />

		<!-- 最小空闲连接数 -->
		<property name="minIdle" value="<#noparse>${</#noparse>jdbc.minIdle}" />

		<!-- 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 -->
		<property name="timeBetweenEvictionRunsMillis"
			value="<#noparse>${</#noparse>jdbc.timeBetweenEvictionRunsMillis}" />

		<!-- 配置一个连接在池中最小生存的时间,单位是毫秒 -->
		<property name="minEvictableIdleTimeMillis"
			value="<#noparse>${</#noparse>jdbc.minEvictableIdleTimeMillis}" />

		<property name="validationQuery"
			value="<#noparse>${</#noparse>jdbc.validationQuery}" />
		<property name="testWhileIdle" value="<#noparse>${</#noparse>jdbc.testWhileIdle}" />
		<property name="testOnBorrow" value="<#noparse>${</#noparse>jdbc.testOnBorrow}" />
		<property name="testOnReturn" value="<#noparse>${</#noparse>jdbc.testOnReturn}" />
		<property name="maxOpenPreparedStatements"
			value="<#noparse>${</#noparse>jdbc.maxOpenPreparedStatements}" />

		<!-- 超过时间限制是否回收 -->
		<property name="removeAbandoned"
			value="<#noparse>${</#noparse>jdbc.removeAbandoned}" />

		<!-- 1800 秒,也就是 30 分钟 -->
		<property name="removeAbandonedTimeout"
			value="<#noparse>${</#noparse>jdbc.removeAbandonedTimeout}" />

		<!-- 关闭 abanded 连接时输出错误日志 -->
		<property name="logAbandoned" value="<#noparse>${</#noparse>jdbc.logAbandoned}" />
	</bean>

	<!-- spring和MyBatis完美整合,不需要mybatis的配置映射文件 -->
	<bean id="sqlSessionFactory"
		class="org.mybatis.spring.SqlSessionFactoryBean">
		<property name="dataSource" ref="dataSource" />
		<!-- 自动扫描mapping.xml文件 -->
		<property name="mapperLocations">
			<array>
				<value>classpath*:/${packageName}/sqlmapper/*.xml</value>
			</array>
		</property>
	</bean>

	<!-- DAO接口所在包名,Spring会自动查找其下的类 -->
	<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
		<property name="annotationClass"
			value="org.springframework.stereotype.Repository" />
		<property name="basePackage" value="${packageName}.dao" />
		<property name="sqlSessionFactoryBeanName"
			value="sqlSessionFactory"></property>
	</bean>

	<!-- (事务管理)transaction manager, use JtaTransactionManager for global tx -->
	<bean id="transactionManager"
		class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
		<property name="dataSource" ref="dataSource" />
	</bean>

	<tx:advice id="advice"
		transaction-manager="transactionManager">
		<tx:attributes>
			<tx:method name="add*" propagation="REQUIRED" />
			<tx:method name="del*" propagation="REQUIRED" />
			<tx:method name="upda*" propagation="REQUIRED" />
			<tx:method name="select*" read-only="true"></tx:method>
			<tx:method name="likeSelect*" read-only="true"></tx:method>
		</tx:attributes>
	</tx:advice>

	<!-- 切入点 -->
	<aop:config>
		<aop:pointcut id="mypoint"
			expression="execution(* ${packageName}.service.impl.*.*(..))"></aop:pointcut>
		<aop:advisor advice-ref="advice" pointcut-ref="mypoint"></aop:advisor>
	</aop:config>

</beans>  

这是个非常经典的springmvc的配置文件,相信大家都非常熟悉。事务上首先配置事务管理器,然后配置事务切面规则,最后设置切入点表达式,跟springboot代码配置的原理是一样的,只是springmvc采用了xml的配置方式

logback日志支持

日志对于一个系统的重要性不言而喻,他对于我们监控系统的运行状态,排查bug等有着不可替代的作用。相信很多朋友现在还在使用log4j,是时候考虑logback了,据说他的性能比log4j优秀数十倍。配置采用xml的配置方式,跟log4j的配置方法大同小异,在springboot中默认原生支持logback,而在springmvc当中使用logback需要引入相关的jar包依赖,并在web,xml当中配置监听器方能使用,关于jar包依赖大家可以使用生成器随便生成一个ssm项目自行查看。

对于logback的支持添加了logback.ftl,webXml.ftl模板,logback.ftl代码如下:

<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="60 seconds"
	debug="false">
	<contextName>logback</contextName>
	<!--输出到控制台 -->
	<appender name="console"
		class="ch.qos.logback.core.ConsoleAppender">
		<!-- <filter class="ch.qos.logback.classic.filter.ThresholdFilter"> <level>ERROR</level> 
			</filter> -->
		<encoder>
			<pattern>%d{HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n
			</pattern>
		</encoder>
	</appender>

	<!--按天生成日志 -->
	<appender name="logFile"
		class="ch.qos.logback.core.rolling.RollingFileAppender">
		<Prudent>true</Prudent>
		<rollingPolicy
			class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
			<FileNamePattern>
				log/%d{yyyy-MM-dd}/%d{yyyy-MM-dd}.log
			</FileNamePattern>
		</rollingPolicy>
		<layout class="ch.qos.logback.classic.PatternLayout">
			<Pattern>
				%d{yyyy-MM-dd HH:mm:ss} -%msg%n
			</Pattern>
		</layout>
	</appender>

	<!--错误日志统一输出到这里 -->
	<appender name="error"
		class="ch.qos.logback.core.rolling.RollingFileAppender">
		<rollingPolicy
			class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
			<!--日志文件输出的文件名 -->
			<FileNamePattern>
				errorlog/%d{yyyy-MM-dd}/%d{yyyy-MM-dd}.log
			</FileNamePattern>
			<!--日志文件保留天数 -->
			<MaxHistory>365</MaxHistory>
		</rollingPolicy>
		<encoder
			class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
			<!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符 -->
			<pattern> %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} -%msg%n</pattern>
		</encoder>
		<!--日志文件最大的大小 -->
		<triggeringPolicy
			class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
			<MaxFileSize>10MB</MaxFileSize>
		</triggeringPolicy>
		<!-- 所有error日志都在这里 -->
		<filter class="ch.qos.logback.classic.filter.LevelFilter">
			<level>ERROR</level>
			<onMatch>ACCEPT</onMatch>
			<onMismatch>DENY</onMismatch>
		</filter>
	</appender>

	<!-- mybatis打印sql语句 -->
	<logger name="${packageName}.dao" level="DEBUG"></logger>

	<root level="INFO">
		<appender-ref ref="console" />
		<appender-ref ref="logFile" />
		<appender-ref ref="error"/>
	</root>
	
</configuration>

配置方法看一眼自然明了。

webXml.ftl代码如下:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns="http://java.sun.com/xml/ns/javaee"
	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
	id="WebApp_ID" version="3.0">
	<display-name>${projectName}</display-name>
	<!-- Spring和mybatis的配置文件 -->
	<context-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>classpath:spring-mybatis.xml</param-value>
	</context-param>
	
	<context-param>  
        <param-name>logbackConfigLocation</param-name>  
        <param-value>classpath:logback.xml</param-value>
    </context-param>  
    <listener>  
        <listener-class>ch.qos.logback.ext.spring.web.LogbackConfigListener</listener-class>  
    </listener> 
	
	<!-- 编码过滤器 -->
	<filter>
		<filter-name>encodingFilter</filter-name>
		<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
		<async-supported>true</async-supported>
		<init-param>
			<param-name>encoding</param-name>
			<param-value>UTF-8</param-value>
		</init-param>
	</filter>
	<filter-mapping>
		<filter-name>encodingFilter</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>

	<!-- druid连接池 启用 Web 监控统计功能 start -->
	<filter>
		<filter-name>DruidWebStatFilter</filter-name>
		<filter-class>com.alibaba.druid.support.http.WebStatFilter</filter-class>
		<init-param>
			<param-name>exclusions</param-name>
			<param-value>*.js ,*.gif ,*.jpg ,*.png ,*.css ,*.ico ,/druid/*</param-value>
		</init-param>
	</filter>

	<filter-mapping>
		<filter-name>DruidWebStatFilter</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>

	<servlet>
		<servlet-name>DruidStatView</servlet-name>
		<servlet-class>com.alibaba.druid.support.http.StatViewServlet</servlet-class>
	</servlet>

	<servlet-mapping>
		<servlet-name>DruidStatView</servlet-name>
		<url-pattern>/druid/*</url-pattern>
	</servlet-mapping>
	<!-- druid连接池 启用 Web 监控统计功能 end -->

	<!-- Spring监听器 -->
	<listener>
		<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
	</listener>
	<!-- 防止Spring内存溢出监听器 -->
	<listener>
		<listener-class>org.springframework.web.util.IntrospectorCleanupListener</listener-class>
	</listener>

	<!-- Spring 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>
		<async-supported>true</async-supported>
	</servlet>
	<servlet-mapping>
		<servlet-name>SpringMVC</servlet-name>
		<url-pattern>/</url-pattern>
	</servlet-mapping>
</web-app>

可以看到配置了LogbackConfigListener来对logback.xml进行解析,从而按照相应的规则生成日志。在这里提一句,生成器的数据库连接池依然使用druid,前台的模板引擎依然使用thymeleaf,跟springboot保持一致,关于为何使用thymeleaf,主要是懒得改模板了,哈哈,毕竟前台不是强项,如果大家有好的前台样式模板欢迎推荐给我,目前只有一套bootstrap。

SSM框架支持

虽说现在springboot越来越火,但是ssm依然为很多个人和公司所用,他代表了一个时代。新版的代码生成器已经可以完美生成ssm项目,导入eclipse、idea发布到tomcat即可运行。但是有一个问题很奇怪,生成的ssm项目在运行的过程中有时会报java.lang.NoClassDefFoundError: org/springframework/web/context/request/async/CallableProcessingInte这个错误,但是clean一下tomcat重新发布项目即可正常运行,也就没再管它,欢迎知道的大佬告知!

运行效果

现在一起来看一下生成器的运行效果吧,以ssm项目为例,这里我就只截图了,不懂的朋友请翻阅之前的博客查看

 

生成代码的时候加入了一个友情提示,确认相关的信息

去eclipse/idea中导入生成的项目,发布到tomcat运行,建议使用tomcat8.5

本次更新到此结束,感谢观看!

  • 7
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值