(转)Nutz | Nutz项目整合Spring实战
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去管理了。
目标
- 原有nutz的业务代码不需要改动能正常运行
- 新做的spring的代码可以正常运行
- nutz可以引用spring的代码
- spring可以引用nutz的代码
方案
- 保留两套MVC,Spring MVC与Nutz MVC共存,原有旧代码继续走Nutz MVC
- Nutz与Spring统一使用Spring IOC容器进行管理,均从Spring上下文查找bean
- 原有Nutz配置搬到Spring ,由Spring统一加载与管理,AOP与事务均使用Spring实现
思路
- Nutz Mvc 与 Spring Mvc相互独立存在,项目原有代码继续使用Nutz Mvc,新建Spring代码采用Spring Mvc,根据请求路径中的前缀/spring/进行切换。
- 原有Nutz项目的bean与新做的spring相关bean统一交给springIOC容器管理,覆盖NutzIOC注解(IocBean、Inject、InjectName)使这些注解标注的类实例交由Spring管理
- 创建SpringIocProvider实现Ioc、IocProvider,使原有Nutz代码与新代码上下文统一使用applicationContext
- 通过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.改造前后兼容测试
测试案例
- 浏览器输入:localhost:8080/evanshare,跳转到登陆页面,输入:admin 123456
- 点击资管管理-用户列表
- 点击资管管理-Sql查询
- 点击资管管理-基于Springle实现用户列表
- 点击资管管理-基于Springle实现Sql查询
预期结果
- 能正常登陆,进入管理后台
- 能正常打开用户列表
- 输入select * from tb_at_user ,能正常导出报表
- 能正常打开用户列表
- 输入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
测试案例
- 执行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实战相关推荐
- 【转】Nutz | Nutz项目整合Spring实战
http://blog.csdn.net/evan_leung/article/details/54767143 Nutz项目整合Spring实战 前言 Github地址 背景 实现步骤 加入spri ...
- Nutz | Nutz项目整合Spring实战
Nutz项目整合Spring实战 前言 Github地址 背景 实现步骤 加入springMvc与Spring 相关配置 新增Spring相关配置 新增SpringIocProvider 重写Nutz ...
- java项目整合mybatis_JavaWeb项目整合Spring,SpringMVC,Mybatis框架
衔接上篇: 版本信息 spring 4.4.13 mybatis 3.4.1 One Step! 根据所需,导入相应jar包,添加依赖. //spring 系列包 4.4.13 // spring m ...
- 我把Github上最牛b的Java教程和实战项目整合成了一个PDF文档
写在前面 大家都知道 Github 是一个程序员福地,这里有各种厉害的开源框架.软件或者教程.这些东西对于我们学习和进步有着莫大的进步,所以我有了这个将 Github 上非常棒的 Java 开源项目整 ...
- 猿创征文 | 微服务 Spring Boot 整合Redis 实战开发解决高并发数据缓存
文章目录 一.什么是 缓存? ⛅为什么用缓存? ⚡如何使用缓存 二.实现一个商家缓存 ⌛环境搭建 ♨️核心源码 ✅测试接口 三.采用 微服务 Spring Boot 注解开启缓存 ✂️@CacheEn ...
- Spring Boot + BeetlSQL + H2数据库项目整合
Spring Boot + BeetlSQL + H2数据库项目整合 这个项目是一个大佬给的,目的是看我的自学能力和基础知识的牢固程度,要求如下: 底层架构采用springboot 前端技术使用lay ...
- spring mvc学习(60):ssm项目整合
SSM整合 建立springmvc项目,先跑起来,再整合spring和mybatis 一.SpringMVC建立 1.新建maven工程,安装tomcat 2.导入pom <!-- spring ...
- Spring Boot 项目使用Spring Security防护CSRF攻击实战
Spring Boot与Spring Security Spring Boot项目结合Spring Security ,可以实现用户认证和用户授权. Spring Security的用户认证可以是配置 ...
- Docker 部署 SpringBoot 项目整合 Redis 镜像做访问计数Demo
Docker 部署SpringBoot项目整合 Redis 镜像做访问计数Demo 最终效果如下 大概就几个步骤 1.安装 Docker CE 2.运行 Redis 镜像 3.Java 环境准备 4. ...
最新文章
- nodejs pm2使用
- 如何进行机器学习框架选择
- 动态调频DVFS_转
- 在大公司工作3年以上的人,如何摆脱螺丝钉的现实?
- Redux入门之实现一个迷你版的Redux
- linux 卸载 flash,使用率下降到8%,Chrome 87将完全移除Flash
- shell脚本获取绝对路径
- python在工厂中的运用_在python中使用元类实现工厂设计模式
- 蛋壳公寓回应破产传闻:没有破产 也不会跑路
- 【Flink】Flink 实现 AT_LEAST_ONCE EXACTLY_ONCE 案例
- csp2020 j2民间数据下载_摊开母婴市场数据集看一看
- CW3 Clarifications
- ReactNative字体大小不随系统字体大小变化而变化
- [HDU2294]Pendant
- iperf简介与下载安装
- 数据可视化1—蒙特卡罗光线追踪
- java开发基础知识学习总结
- 惠普HP LaserJet Pro M405d 打印机驱动
- Maven学习(一) --------- Maven 简介
- 基于ITK的读并写 2D的DICOM 图像
热门文章
- 注解返回html页面,【提问】ajax请求返回整个html页面
- (28)XIlinx FPGA 原语简介(FPGA不积跬步101)
- (62)FPGA一维数组(reg)
- (31)FPGA原语设计(IBUFG)
- java中获取XML中的子xml_如何将子元素从XML提取到Java中的字符串?
- 的使用两个数据集拼接_使用Scikit Learn的分类器探索Iris数据集
- 集成springboot案例_SpringBoot开发者都在用的五款优质扩展,每个都很能打!
- TCP和UDP服务器性能测试工具
- docker 日志_Filebeat 采集 Docker 日志
- NAPI 技术在 Linux 网络驱动上的应用和完善