【转】Nutz | Nutz项目整合Spring实战
http://blog.csdn.net/evan_leung/article/details/54767143
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>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>
注意:以下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]);
    }
    }从以上代码可以看出,该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);
    }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";
    }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);
    }
}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;
    }猜想
基于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);
        }
    }
}回顾之前的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>- 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);
    }
}为什么要过滤?
为了应对基于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.改造前后兼容测试
测试案例
- 浏览器输入: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();
    }
}测试案例
- 执行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【转】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 ... 
- eclipse环境下基于已构建struts2项目整合spring+hibernate
		本文是基于已构建的struts2项目基础上整合 spring+hibernate,若读者还不熟悉struts2项目,请先阅读 eclipse环境下基于tomcat-7.0.82构建struts2项目 ... 
- 通过idea创建Maven项目整合Spring+spring mvc+mybatis
		创建项目 File→new→project 然后就不断next直到项目面板出来 设置文件夹 注意:这里我个人习惯,在java下还建了ssm文件夹,然后再cont ... 
- shiro与Web项目整合-Spring+SpringMVC+Mybatis+Shiro(八)
		Jar包 
- Spring与Web项目整合的原理
		引言: 在刚开始我们接触IOC时,我们加载并启用SpringIOC是通过如下代码手动加载 applicationContext.xml 文件,new出context对象,完成Bean的创建和属性的注入 ... 
- Java Web整合开发实战:基于Struts 2+Hibernate+Spring 目录
		第1篇 Java Web开发基础第1章 Web的工作机制( 教学视频:31分钟) 1.1 理解Web的概念 1.1.1 Web的定义 1.1.2 Web的三个核心标准 1.2 C/S与B/S两种软件体 ... 
- Axis2在Web项目中整合Spring
		一.说明: 上一篇说了Axis2与Web项目的整合(详情 :Axis2与Web项目整合)过程,如果说在Web项目中使用了Spring框架,那么又改如何进行Axis2相关的配置操作呢? 二.Axis2 ... 
- Spring3 + Spring MVC+ Mybatis 3+Mysql 项目整合(注解及源码)
		Spring3 + Spring MVC+ Mybatis 3+Mysql 项目整合(注解及源码) 备注: 之前在Spring3 + Spring MVC+ Mybatis 3+Mysql 项目整合中 ... 
随机推荐
- YTU 2402: Common Subsequence
			2402: Common Subsequence 时间限制: 1 Sec 内存限制: 32 MB 提交: 63 解决: 33 题目描述 A subsequence of a given seque ... 
- mysql查询表的字符集
			mysql查询表的字符集 SHOW CREATE TABLE user; 
- robotframework 随机选中下拉框中的值
			示例脚本: click element id=provinceName #点击地区 省 wait until element is enabled xpath=.//*[@id='provinceNa ... 
- bzoj1951
			CRT+LUCAS+费马小定理+拓展欧拉定理 幂指数太大了怎么办?欧拉定理,n太大了怎么办?上lucas,模数太大了怎么办?上crt.然后就好了,唯一注意的是要用拓展欧拉定理,n%phi(p)+phi ... 
- bzoj4031
			4031: [HEOI2015]小Z的房间 Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 823 Solved: 407[Submit][Statu ... 
- 常见电商项目的数据库表设计(MySQL版)
			转自:https://cloud.tencent.com/developer/article/1164332 简介: 目的: 电商常用功能模块的数据库设计 常见问题的数据库解决方案 环境: MySQL ... 
- vs 中switch语句快捷键列出枚举
			先switch然后两下tab会补完到default,光标显示在switch后的变量这时输入枚举,输完后回车,自动补完所有枚举的case 
- asp.net mvc 学习资料
			ASP.NET MVC 的 WebGrid 的 6 个重要技巧 http://www.oschina.net/translate/webgrid-in-asp-net-mvc-important-ti ... 
- XDCTF2015代码审计全解
			此次CTF WEB2是一个大题,一共4个flag,分别代表:获取源码.拿下前台管理.拿下后台.getshell. 目标站:http://xdsec-cms-12023458.xdctf.win/ 根据 ... 
- hdu4815 概率问题
			题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4815 好久没写dp了..最开始题意都理解错了, 哎!!我现在很饿也很困!! AC代码: #includ ... 
