zoukankan      html  css  js  c++  java
  • Nutz | Nutz项目整合Spring实战

    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>

    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.改造前后兼容测试

    测试案例

    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. 执行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
  • 相关阅读:
    updatepanel中不能使用fileupload的弥补方法
    AJAXPro用法,关于JS同步和异步调用后台代码的学习
    How do I get data from a data table in javascript?
    记不住ASP.NET页面生命周期的苦恼
    浅谈ASP.NET中render方法
    解决AjaxPro2中core.ashx 407缺少对象的问题
    ServU 6.0出来了
    关于X Server/Client和RDP的畅想
    这个Blog好像没有分页功能嘛
    AOC的显示器太烂了
  • 原文地址:https://www.cnblogs.com/evan-liang/p/12233943.html
Copyright © 2011-2022 走看看