http://blog.csdn.net/evan_leung/article/details/54767143

  • Nutz项目整合Spring实战
  • 前言
    • Github地址
  • 背景
  • 实现步骤
    • 加入springMvc与Spring 相关配置
    • 新增Spring相关配置
    • 新增SpringIocProvider
    • 重写Nutz IOC注解
    • 新增spring相关controller与service
    • 事务托管给Spring
    • 修改ResourceFilter
    • 新增基于Spring代码实现的菜单
  • 测试
    • 改造前后兼容测试
    • 事务测试
      • 新建NutzTransTestService

Nutz项目整合Spring实战

前言

本教程主要基于本人Nutz框架的 Demo进行改造,目的是使原有Nutz demo代码可以正常运行,新增spring代码也可以正常运行,并且Nutz框架原有代码与spring新增代码可以相互引用,从而达到整合后的新代码与旧代码可以兼容,请配合项目源码进行操作。

Demo功能

登陆模块 
查看用户列表 
新增用户 
通过自定义sql自动导出报表

Github地址

https://github.com/Evan43789596/evanshare.git

背景

某公司原有项目采用的是Nutz框架,无奈是Nutz框架整合其他主流框架会相对繁琐,加上Nutz对事务支持也不是很友好,而且也不便于团队成员使用和学习市面主流技术,于是我们想把Nutz与spring框架整合,在不影响原有项目的前提下,新代码均使用spring实现,也就意味着把nutz的东西都转移到spring去管理了。

目标

  1. 原有nutz的业务代码不需要改动能正常运行
  2. 新做的spring的代码可以正常运行
  3. nutz可以引用spring的代码
  4. spring可以引用nutz的代码

方案

  1. 保留两套MVC,Spring MVC与Nutz MVC共存,原有旧代码继续走Nutz MVC
  2. Nutz与Spring统一使用Spring IOC容器进行管理,均从Spring上下文查找bean
  3. 原有Nutz配置搬到Spring ,由Spring统一加载与管理,AOP与事务均使用Spring实现

思路

  1. Nutz Mvc 与 Spring Mvc相互独立存在,项目原有代码继续使用Nutz Mvc,新建Spring代码采用Spring Mvc,根据请求路径中的前缀/spring/进行切换。
  2. 原有Nutz项目的bean与新做的spring相关bean统一交给springIOC容器管理,覆盖NutzIOC注解(IocBean、Inject、InjectName)使这些注解标注的类实例交由Spring管理
  3. 创建SpringIocProvider实现Ioc、IocProvider,使原有Nutz代码与新代码上下文统一使用applicationContext
  4. 通过Spring AutowiredAnnotationBeanPostProcessor类中的setAutowiredAnnotationTypes方法,可使开发者扩展自定义注解交给spring去自动注入(如:Inject),从而实现spring的代码也能使用Inject注解 
    把原有nutz项目的所有配置统一交由spring去加载,这样后面的事情都按照spring的方式去做即可。

文件变更

  • 在com.evanshare包下,新增spring相关Controller与service,其功能与原Nutz部分相同
  • 新增SpringIocProvider
  • 修改MainModule原有IocBy的类型,改为SpringIocProvider
  • 新增org.nutz包,用于复写Nutz Ioc相关注解
  • 修改ResourceFilter,新增对/spring/过滤
  • 修改web.xml,加入spring相关配置
  • 在resource目录下新增application.xml、SpringMVC-servlet.xml以及其他相关.xml,把原有Nutz配置搬到 .xml
  • 对com.evanshare.module原有nutz部分module引入spring相关service与注解

实现步骤

1.加入springMvc与Spring 相关配置

打开WEB-INF下的web.xl,在原有配置基础上加入如下配置

<!--引入spring--><context-param><param-name>contextConfigLocation</param-name> <param-value>classpath*:applicationContext.xml</param-value> <!-- 默认是/WEB-INF/applicationContext.xml --> </context-param> <listener> <listener-class> org.springframework.web.context.ContextLoaderListener </listener-class> </listener> <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-servlet.xml</param-value> <!-- 默认是/WEB-INF/[servlet名字]-servlet.xml --> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>SpringMVC</servlet-name> <url-pattern>/spring/*</url-pattern> </servlet-mapping>

2.新增Spring相关配置

在resource目录下,创建applicationContext.xml,加入如下配置

<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd"> <import resource="conf/*.xml" /> </beans>

在resource目录下,创建SpringMVC-servlet.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:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd"> <!-- 设置使用注解的类所在的jar包 --> <context:component-scan base-package="com.evanshare" /> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix"> <value>/WEB-INF/jsp/</value> </property> <property name="suffix"> <value>.jsp</value> </property> </bean> </beans>

在Resource下,分别创建jdbc.xml、nutDao.xml、property.xml、transation.xml、annotation.xml

jdbc.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" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd"> <!-- druid--> <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"> <property name="driverClassName" value="${db.driver}"/> <property name="url" value="${db.url}"/> <property name="username" value="${db.username}" /> <property name="password" value="${db.password}"/> <property name="testWhileIdle" value="true"/> <property name="validationQuery" value="${db.validationQuery}"/> <property name="maxActive" value="${db.maxActive}"/> <property name="connectionProperties" value="druid.stat.slowSqlMillis=2000"/> </bean> </beans>
  • 1

nutzDao.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" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd"> <bean id="dao" class="org.nutz.dao.impl.NutDao"> <property name="dataSource" ref="dataSource"/> <!-- 如果要使用Trans,移除springDaoRunner --> <property name="runner" ref="springDaoRunner"/> </bean> <bean id="springDaoRunner" class="org.nutz.integration.spring.SpringDaoRunner"> </bean> </beans>

property.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" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd"> <!-- 读取jdbc配置 --> <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> <property name="locations"> <list> <!-- jdbc配置 --> <value>classpath:properties/db.properties</value> </list> </property> </bean> </beans>

transation.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" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd"> <bean id="dao" class="org.nutz.dao.impl.NutDao"> <property name="dataSource" ref="dataSource"/> <!-- 如果要使用Trans,移除springDaoRunner --> <property name="runner" ref="springDaoRunner"/> </bean> <bean id="springDaoRunner" class="org.nutz.integration.spring.SpringDaoRunner"> </bean> </beans>

annotation.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:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd"> <!--spring 扫包 @Service .....--> <context:component-scan base-package="com.evanshare"> <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/> </context:component-scan> <context:annotation-config/> <!-- 添加自定义注解,使spring自动注入--> <bean class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor"> <property name="autowiredAnnotationTypes" > <set > <value >org.nutz.ioc.loader.annotation.Inject</value> </set> </property> </bean> </beans>
  • 1

注意:

以下annotation.xml中的这段配置,是为了让spring能识别我们的自定义注解,并且能为我们用自定义注解(Nutz的@Inject)标识的对象注入,我们如果想加多几个自定义注解,只需要像一下配置那样把全限定类名加入到属性中即可

 <!-- 添加自定义注解,使spring自动注入--><bean class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor"> <property name="autowiredAnnotationTypes" > <set > <value >org.nutz.ioc.loader.annotation.Inject</value> </set> </property> </bean>

Tips

为什么我会知道?参考Spring AutowiredAnnotationBeanPostProcessor源码注释可以看到,其实它本身就是支持开发者自由扩展的

    /*** Set the 'autowired' annotation types, to be used on constructors, fields,* setter methods and arbitrary config methods.* <p>The default autowired annotation type is the Spring-provided* {@link Autowired} annotation, as well as {@link Value}.* <p>This setter property exists so that developers can provide their own* (non-Spring-specific) annotation types to indicate that a member is* supposed to be autowired.*/public void setAutowiredAnnotationTypes(Set<Class<? extends Annotation>> autowiredAnnotationTypes) {Assert.notEmpty(autowiredAnnotationTypes, "'autowiredAnnotationTypes' must not be empty"); this.autowiredAnnotationTypes.clear(); this.autowiredAnnotationTypes.addAll(autowiredAnnotationTypes); }

3.新增SpringIocProvider,

具体SpringIocProvider代码请查看项目源码,主要看下面这段代码:

public class SpringIocProvider implements IocProvider, Ioc { protected ApplicationContext applicationContext; @Override public Ioc create(NutConfig config, String[] args) { if (config == null || Lang.length(args) > 0) applicationContext = new ClassPathXmlApplicationContext(args); else applicationContext = (ApplicationContext) config.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE); return this; } @SuppressWarnings("unchecked") @Override public <T> T get(Class<T> classZ) throws IocException { InjectName injectName = classZ.getAnnotation(InjectName.class); if (injectName != null && !Strings.isBlank(injectName.value())) return (T) applicationContext.getBean(injectName.value()); return (T) applicationContext.getBean(applicationContext.getBeanNamesForType(classZ)[0]); } }
  • 1

从以上代码可以看出,该create和get方法会返回一个applicationContext,也就是说,Nutz Ioc如果是使用该iocProvider去创建,那么Nutz 在查找bean的时候将会从spring的上下文中去查找了,从而达到了我们想要的spring管理bean的效果,可对比Nutz原生ComboIocProvider.

在主模块声明SpringIocProvider 
在MainModule上加入@IocBy(type=SpringIocProvider.class,args={})

@ChainBy(args="conf/mvc/evanshare-mvc-chain.js")
@SetupBy(value=MainSetup.class)
//@IocBy(type=CustomComboIocProvider.class,args={"*js","conf/ioc/","*anno","com.evanshare","*tx"})
@IocBy(args = {} ,type = SpringIocProvider.class) @Modules(scanPackage=true) @Fail("jsp:jsp.500") @Localization(value="msg/", defaultLocalizationKey="zh-CN") public class MainModule { } 

意味着nutz的所有bean都将会从spring上下文中查找

4.重写Nutz IOC注解

为了使项目中原有nutz IOC注解标识的类能交给spring容器管理,我们需要做一些小的改动,就是在原注解上加入spring的注解@Component,这样的话,spring就会帮我们将这些类纳入到spring容器管理.需要重写的注解有:@Inject、@IocBean、@InjectName,以下取IocBean作为示例,其他同理。

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Component public @interface IocBean {

5.新增spring相关controller与service

在com.evanshare包下,新建Spring相关Controller: SpUserController、SpSqlController,新建Spring相关Service:SpUserService、SpSqlService

作用

SpUserController:基于spring实现,用于用户操作相关模块,作用与Nutz demo中的UserModule相同,用于用户登录、添加用户、用户列表展示

SpSqlController:基于Spring实现,用于Sql查询相关模块,作用与Nutz demo中的SqlController中的SqlModule相同,用于根据sql导出报表

SpUserService:基于Spring实现,用于用户相关处理逻辑, 
与Nutz demo中的UserService作用相同,可互相替换使用

SpSqlService:基于Spring实现,用于sql相关处理逻辑, 
与Nutz demo中的SqlService作用相同,可互相替换使用

SpUserController

/**** 基于spring实现的Sql Controller* Created by liangyh on 2017/1/24.* Email:10856214@163.com*/
@Controller
public class SpSqlController { @Autowired private SpSqlService spSqlService; //注入nutz service @Inject private SqlService sqlService; /** * 跳转到sql查询页面 * @return */ @RequestMapping(value = "/sql/sql_query") public String forwardToSqlQuery(){ return "sql/sql_query"; } /** * 根据自定义sql到处报表 * @param querySql * @param resp * @throws Exception */ @RequestMapping("/sql/exportData") public void exportSqlData(@RequestParam(value = "querySql",required = false) String querySql, HttpServletResponse resp) throws Exception { spSqlService.exportExcelBySql(querySql,resp); //调用Nutz service去到处报表 // sqlService.exportExcelBySql(querySql,resp); }
  • 1

SpUserController

/*** 基于spring实现的用户controller* Created by liangyh on 2017/1/28.* Email:10856214@163.com*/
@RestController
public class SpUserController { @Autowired private SpUserService spUserService; //注入nutz的service @Inject private UserService userService; /** * 用户登录 * * @param name * @param password * @param session * @return */ @RequestMapping("/user/login") public String login(@RequestParam("username") String name, @RequestParam("password") String password, HttpSession session) { User user = spUserService.findByNameAndPsw(name,password); if (user == null) { return "/page/error/500"; } else { session.setAttribute("user", user); return "jsp/common/index_menu"; } } /** * 获取用户列表 * * @param session * @return */ @RequestMapping("/user/list") public String list(@RequestParam(value = "pageNum",required = false) String pageNum,@RequestParam(value = "numPerPage",required = false) String numPerPage ,@RequestParam(value = "keyword",required = false) String keyword,HttpSession session,HttpServletRequest req) { Integer page = StringUtils.isNotBlank(pageNum)?Integer.parseInt(pageNum):0; Integer perPageNum = StringUtils.isNotBlank(numPerPage)?Integer.parseInt(numPerPage):0; //调用Nutz service获取用户列表 // QueryResult result = userService.getUserList(page, perPageNum,keyword); QueryResult result = spUserService.getUserList(page, perPageNum,keyword); List<User> users = result.getList(User.class); PagerModel pager = new PagerModel(); pager.setCurrentPage(page); pager.setNumPerPage(perPageNum); pager.setPageNumShown(result.getPager().getPageSize()); pager.setTotalCount(result.getPager().getRecordCount()); pager.setPageSize(result.getPager().getPageSize()); req.setAttribute("users", users); req.setAttribute("pager", pager); return "user/user_list"; }
  • 1

SpUserService

/*** 基于spring 的service* Email:10856214@163.com*/
@Service
public class SpUserService { @Autowired private Dao dao; /** * 获取用户列表 * @param pageNumber * @param pageSize * @param keyword * @return */ public QueryResult getUserList(int pageNumber,int pageSize,String keyword){ if(StringUtils.isEmpty(keyword)){ keyword = ""; } Pager pager = dao.createPager(pageNumber, pageSize); List<User> userList =dao.query(User.class, Cnd.where("name","like","%"+keyword+"%"), pager); return new QueryResult(userList,pager); } /** * 根据姓名和密码查找用户 * @param name * @param password * @return */ public User findByNameAndPsw(String name,String password){ return dao.fetch(User.class, Cnd.where("name", "=", name).and("password", "=", password)); } public void print(){ System.out.println("I AM NUTZ SERVICE"); } /** * 获取用户总数 * @return */ public Integer getTotalUserCount(){ return dao.count(User.class); } /** * 添加用户 * @param user * @return */ public User addUser(User user) { user.setCreateTime(new Date()); user.setUpdateTime(new Date()); return dao.insert(user); } }
  • 1

SpSqlService

/*** Created by liangyh on 2017/1/28.* Email:10856214@163.com*/
@Service
public class SpSqlService { private final Logger logger = Logger.getLogger(SqlModule.class); @Autowired private Dao dao; /** * 根据自定义sql导出报表 * @param insql 自定义sql * @param resp 响应实体 * @throws SQLException * @throws IOException * @throws FileNotFoundException * @throws JSQLParserException */ public void exportExcelBySql(String insql,HttpServletResponse resp) throws Exception { // 11:创建一个excel SXSSFWorkbook book = new SXSSFWorkbook(1000); java.sql.ResultSet rs = null; List<String> tables = getTables(insql); DataSource datasource = Mvcs.getIoc().get(DruidDataSource.class, "dataSource"); Connection conn = null; Statement st =null; try { conn = datasource.getConnection(); // 3:声明st double maxRowNum; int sheets; ResultSetMetaData rsmd; int cols; long startTime; long endTime; st = conn.createStatement(); //结果集总行数 double totalcount = 137713; /* excel单表最大行数是65535 */ maxRowNum = 60000; sheets = (int) Math.ceil(totalcount / maxRowNum); rs = st.executeQuery(insql); // 3:rsmd rsmd = (ResultSetMetaData) rs.getMetaData(); // 4:分析一共多少列 cols = rsmd.getColumnCount(); startTime = System.currentTimeMillis(); //写入excel文件数据信息 for (int i = 0; i < sheets; i++) { logger.info("<=======正在导出报表=========>"); // 12:创建sheet SXSSFSheet sheet = book.createSheet(" " + (i + 1) + " "); // 13:创建表头 SXSSFRow row = sheet.createRow(0); for (int j = 0; j < cols; j++) { String cname = rsmd.getColumnName(j + 1); SXSSFCell cell = row.createCell(j); cell.setCellValue(cname); } // 显示数据 for (int t = 0; t < maxRowNum; t++) { if (!rs.next()) { break; } // 14:保存数据 row = sheet.createRow(sheet.getLastRowNum() + 1); for (int j = 0; j < cols; j++) { SXSSFCell cell = row.createCell(j); cell.setCellValue(rs.getString(j + 1)); } } } resp.reset(); resp.setContentType("multipart/form-data"); //自动识别 resp.setHeader("Content-Disposition", "attachment;filename=data.xls"); book.write(resp.getOutputStream()); endTime = System.currentTimeMillis(); logger.info("导出报表所用时间为:" + (endTime - startTime)); }catch (Exception ex){ logger.info(String.format("导出报表异常,Sql=【%s】,异常信息{}",insql),ex); }finally { if(book!=null){ book.close(); } if(rs!=null){ rs.close(); } if(st!=null){ st.close(); } if(conn!=null){ conn.close(); } } } /** * 获取对应的表 * @param insql 自定义sql * @return * @throws JSQLParserException */ private List<String> getTables(String insql) throws JSQLParserException{ net.sf.jsqlparser.statement.Statement statement = CCJSqlParserUtil.parse(insql); Select selectStatement = (Select)statement; TablesNamesFinder tablesNamesFinder = new TablesNamesFinder(); List<String> result = tablesNamesFinder.getTableList(selectStatement); return result; }
  • 1

猜想

基于Spring实现的SpUserService与基于Nutz实现的UserService相互替换使用,Spring实现的Controller既然调用spring的service,也能调用nutz的service(SpSqlService与SqlService同理)

6.事务托管给Spring

在org.nutz下创建SpringDaoRunner,SpringDaoRunner继承NutDaoRunner,重写了_run方法,通过DataSourceUtils去获取connection,使得事务可以统一交给Spring去管理

public class SpringDaoRunner extends NutDaoRunner { @Override public void _run(DataSource dataSource, ConnCallback callback) { Connection con = DataSourceUtils.getConnection(dataSource); try { callback.invoke(con); } catch (Exception e) { if (e instanceof RuntimeException) throw (RuntimeException) e; else throw new RuntimeException(e); } finally { DataSourceUtils.releaseConnection(con, dataSource); } } }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

回顾之前的nutDao.xml配置,该配置作用是使用spring管理事务

<bean id="dao" class="org.nutz.dao.impl.NutDao"> <property name="dataSource" ref="dataSource"/> <!-- 如果要使用Trans,移除springDaoRunner --> <property name="runner" ref="springDaoRunner"/> </bean> <bean id="springDaoRunner" class="org.nutz.integration.spring.SpringDaoRunner"> </bean>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

7.修改ResourceFilter

在ResourceFilter中的init方法中,新增对请求路径中/spring/过滤

/*** 对资源文件进行过滤* @author lyh**/
public class ResourceFilter extends NutFilter { protected Set<String> prefixs = new HashSet<String>(); @Override public void init(FilterConfig conf) throws ServletException { super.init(conf); prefixs.add(conf.getServletContext().getContextPath() + "/druid/"); //对请求路径带有/spring/过滤 prefixs.add(conf.getServletContext().getContextPath() + "/spring/"); } @Override public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException { if (req instanceof HttpServletRequest) { String uri = ((HttpServletRequest) req).getRequestURI(); for (String prefix : prefixs) { if (uri.startsWith(prefix)) { chain.doFilter(req, resp); return; } } } super.doFilter(req, resp, chain); } }
  • 1

为什么要过滤?

为了应对基于spring controller请求可以走Spring Mvc,所以在ResourceFilter那进行了过滤,避免被NutFilter进行拦截和调用到Nutz MVC的处理方法,这样请求可以顺利进入DispatcherServlet

8.新增基于Spring代码实现的菜单

在原Nutz demo菜单基础上,新增两个指向Spring处理类的菜单,只想Spring处理类的Url前缀都加上/spring/,用于区分请求是走Spring MVC还是Nutz Mvc

    <ul class="tree treeFolder"><li><a href="<%=request.getContextPath() %>/user/list" target="navTab" rel="user_list">用户列表</a></li> </ul> </li> </ul> <ul class="tree treeFolder"> <li><a href="<%=request.getContextPath() %>/sql/sql_query" target="navTab" rel="sql_query">SQL查询</a></li> </ul> </li> </ul> <ul class="tree treeFolder"> <li><a href="<%=request.getContextPath() %>/spring/user/list" target="navTab" rel="spring_user_list">基于Srping实现用户列表</a></li> </ul> </li> </ul> <ul class="tree treeFolder"> <li><a href="<%=request.getContextPath() %>/spring/sql/sql_query" target="navTab" rel="springsql_query">基于Spring实现SQL查询</a></li> </ul> </li> </ul>
  • 1

菜单显示如下 

测试

1.改造前后兼容测试

测试案例

  1. 浏览器输入:localhost:8080/evanshare,跳转到登陆页面,输入:admin 123456
  2. 点击资管管理-用户列表
  3. 点击资管管理-Sql查询
  4. 点击资管管理-基于Springle实现用户列表
  5. 点击资管管理-基于Springle实现Sql查询

预期结果

  1. 能正常登陆,进入管理后台
  2. 能正常打开用户列表
  3. 输入select * from tb_at_user ,能正常导出报表
  4. 能正常打开用户列表
  5. 输入select * from tb_at_user ,能正常导出报表

2.事务测试

新建NutzTransTestService

在com.evanshare.spring.service包下,新建NutzTransTestService

package com.evanshare.spring.service;import org.nutz.dao.Dao;
import org.springframework.transaction.annotation.Transactional;/*** 该类用于事务测试用途* Created by liangyh on 2017/1/28.* Email:10856214@163.com*/
public class NutzTransTestService { protected Dao dao; public void setDao(Dao dao) { this.dao = dao; } @Transactional(rollbackFor=Exception.class) public void doUserClear() { dao.clear("tb_at_user"); throw new RuntimeException(); } } 

在Test目录下com.evanshare.spring.service包新建NutzTransTestServiceTest

package com.evanshare.spring.service;import org.junit.Test;
import org.nutz.dao.Dao;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.util.Assert; import static org.junit.Assert.*; /** * NUtz事务测试 * Created by liangyh on 2017/1/28. * Email:10856214@163.com */ public class NutzTransTestServiceTest extends Assert { @Test public void doUserClear() throws Exception { ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml"); NutzTransTestService nutzTest = ctx.getBean("transTest", NutzTransTestService.class); Dao dao = ctx.getBean("dao", Dao.class); int count = dao.count("tb_at_user"); assertTrue(count > 0); try { nutzTest.doUserClear(); } catch (Exception e) { // 里面主动抛出异常 } assertEquals(count, dao.count("tb_at_user")); ctx.close(); } }
  • 1

测试案例

  1. 执行NutzTransTestServiceTest下的doUserClear方法

预期结果

  • NutzTransTestService有一个spring事务注解的方法,里面清除了t_user表,然后抛出了异常
  • 日志中显示, spring的事务进行了rollback, 可以看到rollback等字眼
  • 执行doUserClear前后的tb_at_user表记录数相同,所以事务真的是回滚了

执行日志如下:

22:17:31.483 [main] DEBUG org.nutz.dao.impl.sql.run.NutDaoExecutor - DELETE FROM tb_at_user 22:17:31.503 [main] DEBUG org.springframework.jdbc.datasource.DataSourceTransactionManager - Initiating transaction rollback 22:17:31.503 [main] DEBUG org.springframework.jdbc.datasource.DataSourceTransactionManager - Rolling back JDBC transaction on Connection [com.mysql.jdbc.JDBC4Connection@2228db21] 22:17:31.511 [main] DEBUG org.springframework.jdbc.datasource.DataSourceTransactionManager - Releasing JDBC Connection [com.mysql.jdbc.JDBC4Connection@2228db21] after transaction 22:17:31.511 [main] DEBUG org.springframework.jdbc.datasource.DataSourceUtils - Returning JDBC Connection to DataSource 22:17:35.556 [main] DEBUG org.springframework.jdbc.datasource.DataSourceUtils - Fetching JDBC Connection from DataSource 22:17:35.556 [main] DEBUG org.nutz.dao.impl.sql.run.NutDaoExecutor - SELECT COUNT(*) FROM tb_at_user 22:17:35.558 [main] DEBUG org.springframework.jdbc.datasource.DataSourceUtils - Returning JDBC Connection to DataSource

转载于:https://www.cnblogs.com/telwanggs/p/7484536.html

(转)Nutz | Nutz项目整合Spring实战相关推荐

  1. 【转】Nutz | Nutz项目整合Spring实战

    http://blog.csdn.net/evan_leung/article/details/54767143 Nutz项目整合Spring实战 前言 Github地址 背景 实现步骤 加入spri ...

  2. Nutz | Nutz项目整合Spring实战

    Nutz项目整合Spring实战 前言 Github地址 背景 实现步骤 加入springMvc与Spring 相关配置 新增Spring相关配置 新增SpringIocProvider 重写Nutz ...

  3. java项目整合mybatis_JavaWeb项目整合Spring,SpringMVC,Mybatis框架

    衔接上篇: 版本信息 spring 4.4.13 mybatis 3.4.1 One Step! 根据所需,导入相应jar包,添加依赖. //spring 系列包 4.4.13 // spring m ...

  4. 我把Github上最牛b的Java教程和实战项目整合成了一个PDF文档

    写在前面 大家都知道 Github 是一个程序员福地,这里有各种厉害的开源框架.软件或者教程.这些东西对于我们学习和进步有着莫大的进步,所以我有了这个将 Github 上非常棒的 Java 开源项目整 ...

  5. 猿创征文 | 微服务 Spring Boot 整合Redis 实战开发解决高并发数据缓存

    文章目录 一.什么是 缓存? ⛅为什么用缓存? ⚡如何使用缓存 二.实现一个商家缓存 ⌛环境搭建 ♨️核心源码 ✅测试接口 三.采用 微服务 Spring Boot 注解开启缓存 ✂️@CacheEn ...

  6. Spring Boot + BeetlSQL + H2数据库项目整合

    Spring Boot + BeetlSQL + H2数据库项目整合 这个项目是一个大佬给的,目的是看我的自学能力和基础知识的牢固程度,要求如下: 底层架构采用springboot 前端技术使用lay ...

  7. spring mvc学习(60):ssm项目整合

    SSM整合 建立springmvc项目,先跑起来,再整合spring和mybatis 一.SpringMVC建立 1.新建maven工程,安装tomcat 2.导入pom <!-- spring ...

  8. Spring Boot 项目使用Spring Security防护CSRF攻击实战

    Spring Boot与Spring Security Spring Boot项目结合Spring Security ,可以实现用户认证和用户授权. Spring Security的用户认证可以是配置 ...

  9. Docker 部署 SpringBoot 项目整合 Redis 镜像做访问计数Demo

    Docker 部署SpringBoot项目整合 Redis 镜像做访问计数Demo 最终效果如下 大概就几个步骤 1.安装 Docker CE 2.运行 Redis 镜像 3.Java 环境准备 4. ...

最新文章

  1. nodejs pm2使用
  2. 如何进行机器学习框架选择
  3. 动态调频DVFS_转
  4. 在大公司工作3年以上的人,如何摆脱螺丝钉的现实?
  5. Redux入门之实现一个迷你版的Redux
  6. linux 卸载 flash,使用率下降到8%,Chrome 87将完全移除Flash
  7. shell脚本获取绝对路径
  8. python在工厂中的运用_在python中使用元类实现工厂设计模式
  9. 蛋壳公寓回应破产传闻:没有破产 也不会跑路
  10. 【Flink】Flink 实现 AT_LEAST_ONCE EXACTLY_ONCE 案例
  11. csp2020 j2民间数据下载_摊开母婴市场数据集看一看
  12. CW3 Clarifications
  13. ReactNative字体大小不随系统字体大小变化而变化
  14. [HDU2294]Pendant
  15. iperf简介与下载安装
  16. 数据可视化1—蒙特卡罗光线追踪
  17. java开发基础知识学习总结
  18. 惠普HP LaserJet Pro M405d 打印机驱动
  19. Maven学习(一) --------- Maven 简介
  20. 基于ITK的读并写 2D的DICOM 图像

热门文章

  1. 注解返回html页面,【提问】ajax请求返回整个html页面
  2. (28)XIlinx FPGA 原语简介(FPGA不积跬步101)
  3. (62)FPGA一维数组(reg)
  4. (31)FPGA原语设计(IBUFG)
  5. java中获取XML中的子xml_如何将子元素从XML提取到Java中的字符串?
  6. 的使用两个数据集拼接_使用Scikit Learn的分类器探索Iris数据集
  7. 集成springboot案例_SpringBoot开发者都在用的五款优质扩展,每个都很能打!
  8. TCP和UDP服务器性能测试工具
  9. docker 日志_Filebeat 采集 Docker 日志
  10. NAPI 技术在 Linux 网络驱动上的应用和完善