• 项目经验整理 各种技术在真实项目中的应用 有用 自己总结的


    1. 递归在项目中的应用  

    第一个递归目录,或者递归解析XML

     

    在实际项目中,我们往往需要动态生成树形结构的菜单来实现数据的管理,如图1所示;或者是需要动态生成树形的图表结构,如图2所示。这些树形结构往往没有层级限制。

     

    图1 树形菜单结构

     

    树形图表结构

    在此,以图2为例提出问题及解决方案。

    数据库设计:

    列名

    类型

    是否为空

    备注

    Id

    bigint

    编号,主键

    ItemName

    varchar(50)

    子项名称

    StartTime

    datetime

    开始时间

    EndTime

    datetime

    结束时间

    FartherCode

    varchar(50)

    父节点编码,如果值为’0’代表该节点为一级节点

    Code

    varchar(50)

    当前节点编码

    实现:

    (1)读取所有的一级节点,放入DataTable中;

    (2)遍历DataTable的每一行(即DataRow);

    (3)对于给定的DataRow,如果该节点没有根节点,返回对应的字符串,否则,获取该节点的的所有子节点得到DataTable,跳转到第(2)步,最终将所有得到的字符串叠加返回;

    核心算法:

     

    [csharp] view plain copy
     
    1. DataTable dtPlan = ProPlanDao.SelectBySql(base.Conn, "select * from ProPlan where FartherCode='0'"); //获取所有根节点  
    2. string html = string.Empty;  
    3. if (dtPlan.Rows.Count > 0){  
    4.   html += "[";  
    5.   //遍历所有子节点  
    6.   for (int i = 0; i < dtPlan.Rows.Count; i++){  
    7.   html += GetJson(dtPlan.Rows[i]) + ",";}  
    8.   html = html.Substring(0, html.Length - 1) + "]";  
    9. }  
    10. //递归函数  
    11. public string GetJson(DataRow dr){  
    12.   //是否拥有子节点  
    13.   bool hasSon = ProPlanDao.HasSub(base.Conn, Code);  
    14.   //递归出口  
    15.   if (!hasSon){  
    16.   string result = "{"id":" + Id + ",";  
    17.   result += ""rownum":"" + (rowNumber++) + "",";  
    18.   result += ""name":"" + ItemName + "",";  
    19.   result += ""start":"" + StartTime + "",";  
    20.   result += ""end":"" + EndTime + "",";  
    21.        result += ""time":"" + (EndTime - StartTime) + "",";  
    22.        result += ""option":"<a href='#'>添加子任务</a> <a href='#'>编辑</a> <a href='#'>删除</a>"}";  
    23.        return result;  
    24.     }  
    25.   else{  
    26.        DataTable dtSon = ProPlanDao.SelectSub(base.Conn, Code);  
    27.        string result = "{"id":" + Id + ",";  
    28.        result += ""rownum":"" + (rowNumber++) + "",";  
    29.        result += ""name":"" + ItemName + "",";  
    30.        result += ""start":"" + StartTime + "",";  
    31.        result += ""end":"" + EndTime + "",";  
    32.        result += ""time":"" + (EndTime - StartTime) + "",";  
    33.        result += ""option":"<a href='#'>添加子任务</a> <a href='#'>编辑</a> <a href='#'>删除</a>",";  
    34.   result += ""state":"closed",";  
    35.   result += ""children":[";  
    36.   //遍历该节点的所有子节点  
    37.         for (int i = 0; i < dtSon.Rows.Count; i++){  
    38.             result += GetJson(dtSon.Rows[i]) + ",";}  
    39.         result = result.Substring(0, result.Length - 1) + "]}";  
    40.         return result;  
    41.   }  
    42. }  

     

     

     

    2.  2.io读写多级目录能用到么? 有那种统计文件个数的功能需要实现么?    

     

     

    io流读写文件

     

    及内容

    3. 3.多线程在项目中的应用,哪两个或多个线程需要同时运行.  

     

    线程在实际项目中简单的应用

    前段时间开发的项目中有一个office在线预览的功能,我们知道需要实现这个功能一般是

    后台把用户上传的txt啊excel啊word啊先转换成pdf格式,然后使用pdf.js进行前台预览(有的还

    需要转换成swf文件),功能倒是实现了,只是客户反馈提交表单的时候速度比较慢,我试了一下

    ,确实比较慢,大概好几十秒,这个有点无法忍受,所以后台转pdf的那个过程就将其使用线程,

    以异步方式去处理。原理就和如下类似

     

    不使用线程:

     

    [java] view plain copy
     
    1. package thread;  
    2.   
    3. public class SleepTest {  
    4.     public static void main(String[] args) throws Exception {  
    5.         System.out.println("begin");  
    6.         Thread.sleep(5000);//模拟业务场景  
    7.         System.out.println("end");  
    8.     }  
    9. }  

     

    例子很简单,控制台输出begin并且在五秒后打印end

    使用线程

     

    [java] view plain copy
     
    1. package thread;  
    2.   
    3. public class SleepTest {  
    4.     public static void main(String[] args) throws Exception {  
    5.         System.out.println("begin");  
    6.         new Thread(new Runnable() {  
    7.             @Override  
    8.             public void run() {  
    9.                 try {  
    10.                     Thread.sleep(5000);//模拟业务场景  
    11.                 } catch (InterruptedException e) {  
    12.                     e.printStackTrace();  
    13.                 }  
    14.             }  
    15.         }).start();  
    16.         System.out.println("end");  
    17.     }  
    18. }  

    效果,执行后控制台立刻显示begin和end

     

    因为目前我们不需要中间处理的结果,因此可以让它在后台执行,不阻塞主线程。

    另外,也可以使用线程池实现上面的功能,代码如下:

     

    [java] view plain copy
     
    1. package thread;  
    2.   
    3. import java.util.concurrent.Executors;  
    4.   
    5. public class SleepTest {  
    6.     public static void main(String[] args) throws Exception {  
    7.         System.out.println("begin");  
    8.         Executors.newSingleThreadExecutor().submit(new Runnable() {  
    9.             @Override  
    10.             public void run() {  
    11.                 try {  
    12.                     Thread.sleep(5000);// 模拟业务场景  
    13.                 } catch (InterruptedException e) {  
    14.                     e.printStackTrace();  
    15.                 }  
    16.             }  
    17.         });  
    18.         System.out.println("end");  
    19.     }  
    20. }  


    结合实际项目中转pdf的例子

    代码如下:

     

    [java] view plain copy
     
    1. package org.framework.core.extend.swftools;  
    2.   
    3. import org.framework.core.util.FileUtils;  
    4.   
    5. /** 
    6.  * 文件转换调用接口 
    7.  *  
    8.  * @author mosesframe 
    9.  * 
    10.  */  
    11. public class SwfToolsUtil {  
    12.     public static void convert2SWF(final String inputFile) {  
    13.   
    14.         new Thread("文件转化服务") {  
    15.             public void run() {  
    16.                 String extend = FileUtils.getExtend(inputFile);  
    17.                 PDFConverter pdfConverter = new OpenOfficePDFConverter();  
    18.                 SWFConverter swfConverter = new SWFToolsSWFConverter();  
    19.                 if (extend.equals("pdf")) {  
    20.                     // swfConverter.convert2SWF(inputFile,extend);  
    21.                     // 该项目这里注释掉,前台预览使用了pdf.js,因此不需要转换成swf文件了,避免浪费更多的时间  
    22.                 }  
    23.                 if (extend.equals("doc") || extend.equals("docx")  
    24.                         || extend.equals("xls") || extend.equals("pptx")  
    25.                         || extend.equals("xlsx") || extend.equals("ppt")  
    26.                         || extend.equals("txt") || extend.equals("odt")) {  
    27.                     DocConverter converter = new DocConverter(pdfConverter,  
    28.                             swfConverter);  
    29.                     converter.convert(inputFile, extend);  
    30.                 }  
    31.             }  
    32.         }.start();  
    33.   
    34.     }  
    35. }  

     

    4. 4.你们的项目中 文件上传或者图片上传同的是TCP协议么

     

     

    :

    上传文件我们用的是hession

    :

    hessiontcp

     

    tcpudp是传输层的协议

     

    5. 反射:用在封装baseServlet中的获取Class对象  解耦合  配合配置文件做到解耦合 还用在哪了?

    反射用的注意事项

    作者:知乎用户
    链接:https://www.zhihu.com/question/23739003/answer/25519537
    来源:知乎
    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

    通常来说,是的。因为反射破坏了程序的“可静态分析”能力。

    举个例子,大部分ide都会提供对某语法结构find reference的功能 (eclips下ctrl-shift-g,intellij下alt-f7),有的甚至提供列出所有调用栈的功能。这就是一种对代码的静态分析。在我们的团队中,提倡对任何现有方法进行修改之前,都应该先使用find reference查看所有对这个方法的调用位置。保证所做的修改不会在修正某条调用路径上的bug时在其他路径上引入新的bug。

    再者,ide提供的分析功能能帮助你在debug时顺藤摸瓜找到真正的出错位置,以及理解作者原来的意图。

    况且,大部分自动重构的功能都是基于静态分析的。

    我个人觉得,静态语言所以能在近来不断涌现的动态语言冲击下,在大型项目中保持不败之地,一个重要原因就是强大的可静态分析能力。动态语言在IDE的帮助下也提供了一定的静态分析能力,但总不如静态语言来得快捷准确。而使用了反射后,大部分依赖于静态分析的功能都不再可用了。 这就是弃长取短,放弃了静态分析能力,又保留了冗长复杂的语法,那为何不干脆用动态语言呢。

    当然,对于一些知名的library,ide会提供特殊的支持,对反射部分做静态分析。但自己写的代码,一旦用了反射,顺藤摸瓜理解代码的线索就断了。

    基于注解(annotation)的反射可以一定程度上缓解这个问题,因为你还是可以通过注解找到使用位置和处理位置。但是, 动态扫描注解的效率很低,在生产代码普遍的做法是分成“扫描,缓存,查找,调用”四步走,增加了开发和维护的复杂度。如果出现调用错误的bug,真正的错误位置却可能在扫描阶段,不容易定位。

    总的来说,我们团队目前对反射的不成文规则是:
    1. 业务代码中基本不用基于名称的反射。除非经过团队讨论确认非用不可,否则基本上不可能通过代码走查。
    2. 业务代码中使用注解相对宽松,但必须缓存,不能在调用时现场扫描。
    3. 一些基本库中允许对Java Bean使用按名访问的反射调用,但不提倡针对某个或某些具体属性(如果属性集可以罗列出来,那么就说明可以改为直接调用),必须是将属性作为整体来循环处理。此类代码必须有85%以上单元测试覆盖率(原则上底层库都要求85%覆盖率)。

     

     

     

    6. 用到xml配置文件解析器DOM,SAXdom4j解析什么的了么?

    7. 动态代理: 代理类和被代理类 实现同一接口 代理类对被代理类进行增强. 项目中哪用到了?

    先看一下代理模式,这个应该是设计模式中最简单的一个了,类图

    代理模式类图

      代理模式最大的特点就是代理类和实际业务类实现同一个接口(或继承同一父类),代理对象持有一个实际对象的引用,外部调用时操作的是代理对象,而在代理对象的内部实现中又会去调用实际对象的操作

     Java动态代理其实内部也是通过Java反射机制来实现的,即已知的一个对象,然后在运行时动态调用其方法,这样在调用前后作一些相应的处理,这样说的比较笼统,举个简单的例子

       比如我们在应用中有这样一个需求,在对某个类的一个方法的调用前和调用后都要做一下日志操作,

    一个普通的接口

     

    [java] view plain copy
     
     
     
    1. public interface AppService {  
    2.       public boolean createApp(String name);  
    3. }  

     

     

    该接口的默认实现类

     

    [java] view plain copy
     
     
     
    1. public class AppServiceImpl implements AppService {  
    2.     public boolean createApp(String name) {  
    3.         System.out.println("App["+name+"] has been created.");  
    4.         return true;  
    5.     }  
    6. }  

     

     

    日志处理器

     

    [java] view plain copy
     
     
     
    1. public class LoggerInterceptor implements InvocationHandler {//注意实现这个Handler接口  
    2.     private Object target;//目标对象的引用,这里设计成Object类型,更具通用性  
    3.     public LoggerInterceptor(Object target){  
    4.         this.target = target;  
    5.     }  
    6.     public Object invoke(Object proxy, Method method, Object[] arg)  
    7.             throws Throwable {  
    8.         System.out.println("Entered "+target.getClass().getName()+"-"+method.getName()+",with arguments{"+arg[0]+"}");  
    9.         Object result = method.invoke(target, arg);//调用目标对象的方法  
    10.         System.out.println("Before return:"+result);  
    11.         return result;  
    12.     }  
    13. }  

     

    外部调用

     

    [java] view plain copy
     
     
     
    1. public class Main {  
    2.     public static void main(String[] args) {  
    3.         AppService target = new AppServiceImpl();//生成目标对象  
    4.         //接下来创建代理对象  
    5.         AppService proxy = (AppService) Proxy.newProxyInstance(  
    6.                 target.getClass().getClassLoader(),  
    7.                 target.getClass().getInterfaces(), new LoggerInterceptor(target));  
    8.         proxy.createApp("Kevin Test");  
    9.     }  
    10. }  

     此外,可以使用Spring AOP 。

     

    8. 事务:  事务只是在删除和修改的时候用的时候用.? 还有什么情况用事务?

     

    添加事务在实际项目中是必不可少的,事务是用来实现要么全都成功,要么全都不成功, 而主要针对的就是要不成功就全都不成功的问题.

    想象你给你女朋友转账,这边刚扣了钱,你女朋友账户还没收到钱呢,突然出故障了,比如停电了. 那怎么办. 这就涉及到一个关键的知识点:事务. 利用的事务的回滚,把你账户上扣的钱再回滚到你账户上.

     

    本篇采用maven构建war工程涉及主要知识点:

    spring+springMVC+mybatis如何整合,  

    mybatis在写mapper.xml文件时,如何解决参数类型只能传一个的问题

    update语句怎么写

    如何保证正确配置了事务,事务少配一个,就会失效

     

     

    声明式事务介绍:

    声明式事务管理建立在AOP之上的。其本质是对方法前后进行拦截,然后在目标方法开始之前创建或者加入一个事务,在执行完目标方法之后根据执行情况提交或者回滚事务。声明式事务最大的优点就是不需要通过编程的方式管理事务,这样就不需要在业务逻辑代码中掺杂事务管理的代码,只需在配置文件中做相关的事务规则声明(或通过基于@Transactional注解的方式),便可以将事务规则应用到业务逻辑中。

     

            显然声明式事务管理要优于编程式事务管理,这正是spring倡导的非侵入式的开发方式。声明式事务管理使业务代码不受污染,一个普通的POJO对象,只要加上注解就可以获得完全的事务支持。和编程式事务相比,声明式事务唯一不足地方是,后者的最细粒度只能作用到方法级别,无法做到像编程式事务那样可以作用到代码块级别。但是即便有这样的需求,也存在很多变通的方法,比如,可以将需要进行事务管理的代码块独立为方法等等。

             声明式事务管理也有两种常用的方式,一种是基于tx和aop名字空间的xml配置文件,另一种就是基于@Transactional注解。显然基于注解的方式更简单易用,更清爽。实际中两种方式常组合起来使用.本篇的案例项目就是组合使用实现事务功能.

     

    项目结构:


     

    数据库部分:

    数据库中就一张表user

    user表的结构

    user表的数据

     

    代码部分:

    pojo 之 User:

     

    [java] view plain copy
     
    1. package com.qx.pojo;  
    2.   
    3. public class User {  
    4.     private Integer id;  
    5.     private String username;  
    6.     private Integer age;  
    7.     private String sex;  
    8.     private Double salary;  
    9.     private String department;    
    10.       
    11.     // getter and setter 方法  
    12.       
    13. }  

     

    mapper之UserMapper接口:

     

    [java] view plain copy
     
    1. package com.qx.mapper;  
    2.   
    3. import java.util.List;  
    4.   
    5. import org.apache.ibatis.annotations.Param;  
    6.   
    7. import com.qx.pojo.User;  
    8.   
    9. public interface UserMapper {  
    10.   
    11.     public List<User> findAll() throws Exception;  
    12.       
    13.     public void AddUser(User user) throws Exception;  
    14.       
    15.     //更改用户  
    16.     public void updateUserById(@Param("id") Integer id,@Param("username") String name,  
    17.             @Param("age") Integer age,@Param("sex") String sex) throws Exception;  
    18.       
    19. }  

     

    mapper之UserMapper.xml

     

    [html] view plain copy
     
    1. <?xml version="1.0" encoding="UTF-8"?>  
    2. <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >  
    3. <mapper namespace="com.qx.mapper.UserMapper">  
    4.     <select id="findAll" resultType="com.qx.pojo.User">  
    5.         select * from user  
    6.     </select>  
    7.       
    8.     <insert id="AddUser" parameterType="com.qx.pojo.User">  
    9.         <selectKey keyProperty="id" resultType="integer" order="AFTER">  
    10.             SELECT LAST_INSERT_ID()  
    11.         </selectKey>    
    12.         insert into user(username,age,sex,salary,department)  
    13.         values (#{username},#{age},#{sex},#{salary},#{department})  
    14.     </insert>  
    15.       
    16.       
    17.     <!-- 我直接在mapper接口中使用了mybatis的参数注解@Param, 在这里就不用在指明参数类型了-->  
    18.     <!-- 即使你想指明也无法直接指明,因为参数类型只接收一个参数,无法接收多个,@Param就是解决这个问题的 -->  
    19.     <select id="updateUserById">  
    20.         update user set username=#{username},age=#{age},sex=#{sex} where id=#{id}  
    21.     </select>  
    22.       
    23. </mapper>  

     

     

    添加的依赖:

    pom.xml:

    需要特别注意的是这4个,不要导错了.

     

    [html] view plain copy
     
    1. <dependency>  
    2.         <groupId>org.springframework</groupId>  
    3.         <artifactId>spring-aspects</artifactId>  
    4.         <version>4.3.7.RELEASE</version>  
    5.     </dependency>  
    6.     <dependency>  
    7.         <groupId>javax.servlet</groupId>  
    8.         <artifactId>jstl</artifactId>  
    9.         <version>1.2</version>  
    10.     </dependency>  
    11.     <dependency>  
    12.         <groupId>javax.servlet</groupId>  
    13.         <artifactId>javax.servlet-api</artifactId>  
    14.         <version>3.1.0</version>  
    15.     </dependency>  
    16.     <dependency>  
    17.         <groupId>javax.servlet.jsp</groupId>  
    18.         <artifactId>jsp-api</artifactId>  
    19.         <version>2.2</version>  
    20.     </dependency>  



     


    配置文件:

    db.properties

     

    [html] view plain copy
     
    1. jdbc.driver=com.mysql.jdbc.Driver  
    2. jdbc.url=jdbc:mysql:///testtransaction?characterEncoding=utf-8  
    3. jdbc.user=root  
    4. jdbc.password=root  


    mybatis.xml

     

     

    [html] view plain copy
     
    1. <?xml version="1.0" encoding="UTF-8" ?>  
    2. <!DOCTYPE configuration  
    3. PUBLIC "-//mybatis.org//DTD Config 3.0//EN"  
    4. "http://mybatis.org/dtd/mybatis-3-config.dtd">  
    5. <configuration>  
    6.             <plugins>  
    7.             <!--   
    8.             3.4.2版本pagehelper  
    9.             <plugin interceptor="com.github.pagehelper.PageHelper">  
    10.                 <property name="dialect" value="mysql"/>  
    11.             </plugin>  
    12.              -->  
    13.              <!--5.0版本pagehelper -->  
    14.             <plugin interceptor="com.github.pagehelper.PageInterceptor">  
    15.                 <property name="helperDialect" value="mysql"/>  
    16.             </plugin>  
    17.               
    18.     </plugins>  
    19. </configuration>  


    spring之applicationContext.xml

     

     

    [html] view plain copy
     
    1. <?xml version="1.0" encoding="UTF-8"?>  
    2. <beans xmlns="http://www.springframework.org/schema/beans"  
    3.     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
    4.     xmlns:context="http://www.springframework.org/schema/context"  
    5.     xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd  
    6.         http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd">  
    7.   
    8.     <context:component-scan base-package="com.qx"></context:component-scan>  
    9.         <!-- 导入配置文件 -->  
    10.     <context:property-placeholder location="classpath:conf/db.properties"/>  
    11.     <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">  
    12.         <property name="driverClass" value="${jdbc.driver}"></property>  
    13.         <property name="jdbcUrl" value="${jdbc.url}"></property>  
    14.         <property name="user" value="${jdbc.user}"></property>  
    15.         <property name="password" value="${jdbc.password}"></property>  
    16.     </bean>  
    17.       
    18.     <!-- 配置工厂 -->  
    19.     <bean id="sqlSessionFactoryBean" class="org.mybatis.spring.SqlSessionFactoryBean">  
    20.         <property name="dataSource" ref="dataSource"></property>  
    21.         <property name="configLocation" value="classpath:mybatis/mybatis.xml"></property>  
    22.     </bean>  
    23.       
    24.     <!-- 配置扫描mapper文件 -->  
    25.     <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">  
    26.         <property name="basePackage" value="com.qx.mapper"></property>  
    27.     </bean>  
    28. </beans>  


    spring之applicationContext-tran.xml

     

     

    [html] view plain copy
     
    1. <?xml version="1.0" encoding="UTF-8"?>  
    2. <beans xmlns="http://www.springframework.org/schema/beans"  
    3.     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
    4.     xmlns:aop="http://www.springframework.org/schema/aop"  
    5.     xmlns:context="http://www.springframework.org/schema/context"  
    6.     xmlns:tx="http://www.springframework.org/schema/tx"  
    7.     xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd  
    8.         http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd  
    9.         http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd  
    10.         http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd">  
    11.   
    12.     <!-- 事务管理器 -->  
    13.     <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">  
    14.         <property name="dataSource" ref="dataSource"></property>  
    15.     </bean>  
    16.       
    17.     <tx:annotation-driven transaction-manager="transactionManager"/>  
    18.       
    19.     <tx:advice id="txAdvice">  
    20.         <tx:attributes>  
    21.             <!-- 约定优于编码 设置事务详情 -->  
    22.             <tx:method name="get*" read-only="true" propagation="SUPPORTS"/>  
    23.             <tx:method name="find*" read-only="true" propagation="SUPPORTS"/>  
    24.             <tx:method name="select*" read-only="true" propagation="SUPPORTS"/>  
    25.             <tx:method name="add*"/>  
    26.             <tx:method name="save*"/>  
    27.             <tx:method name="insert*"/>  
    28.             <tx:method name="delete*"/>  
    29.             <tx:method name="update*"/>  
    30.         </tx:attributes>  
    31.     </tx:advice>  
    32.       
    33.     <aop:config>  
    34.         <aop:advisor advice-ref="txAdvice" pointcut="execution(* com.qx.service..*.*(..))"/>  
    35.     </aop:config>  
    36. </beans>  


    spring之spring-MVC.xml:

     

     

    [html] view plain copy
     
    1. <?xml version="1.0" encoding="UTF-8"?>  
    2. <beans xmlns="http://www.springframework.org/schema/beans"  
    3.     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
    4.     xmlns:context="http://www.springframework.org/schema/context"  
    5.     xmlns:mvc="http://www.springframework.org/schema/mvc"  
    6.     xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd  
    7.         http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd  
    8.         http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.3.xsd">  
    9.   
    10.     <!-- 再配一遍,只扫描controller -->  
    11.     <context:component-scan base-package="com.qx.controller"></context:component-scan>  
    12.       
    13.     <!-- 不需要 配置id,因为 用不到 -->  
    14.     <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">  
    15.         <!-- <property name="prefix" value="/"></property> -->  
    16.         <property name="suffix" value=".jsp"></property>  
    17.     </bean>  
    18.       
    19.     <!-- 配置resource标签,此标签内部的地址不会被拦截 -->  
    20.     <mvc:resources location="/css/" mapping="/css/**"></mvc:resources>  
    21.     <mvc:resources location="/js/" mapping="/js/**"></mvc:resources>  
    22.     <mvc:resources location="/images/" mapping="/images/**"></mvc:resources>  
    23.   
    24.     <mvc:annotation-driven></mvc:annotation-driven>  
    25. </beans>  


    配置时你也许见到有人在<tx:advice>标签内又配置了一遍transaction-manager,其实完全没必要,配置了也不会报错,要想事务生效的一个关键点是

     

    必须要配置 事务的注解驱动 <tx:annotation-driven transaction-manager="transactionManager"/>

     

    <tx:annotation-driven transaction-manager="transactionManager"/>

    <tx:advice id="txAdvice" transaction-manager="transactionManager">
    <tx:attributes>
    <!-- 约定优于编码 设置事务详情 -->
    <tx:method name="get*" read-only="true" propagation="SUPPORTS"/>
    <tx:method name="find*" read-only="true" propagation="SUPPORTS"/>
    <tx:method name="select*" read-only="true" propagation="SUPPORTS"/>
    <tx:method name="add*"/>
    <tx:method name="save*"/>
    <tx:method name="insert*"/>
    <tx:method name="delete*"/>
    <tx:method name="update*"/>
    </tx:attributes>
    </tx:advice>

     

     

    web.xml中的配置:

     

    [html] view plain copy
     
    1. <?xml version="1.0" encoding="UTF-8"?>  
    2. <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5">  
    3.   <display-name>TestTranSaction</display-name>  
    4.   
    5.     <!-- needed for ContextLoaderListener -->  
    6.     <context-param>  
    7.         <param-name>contextConfigLocation</param-name>  
    8.         <param-value>classpath*:spring/app*.xml</param-value>  
    9.     </context-param>  
    10.   
    11.     <!-- Bootstraps the root web application context before servlet initialization -->  
    12.     <listener>  
    13.         <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>  
    14.     </listener>  
    15.       
    16.     <!-- The front controller of this Spring Web application, responsible for handling all application requests -->  
    17.     <servlet>  
    18.         <servlet-name>springMVC</servlet-name>  
    19.         <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>  
    20.         <init-param>  
    21.             <param-name>contextConfigLocation</param-name>  
    22.             <param-value>classpath:spring/spring-MVC.xml</param-value>  
    23.         </init-param>  
    24.         <load-on-startup>2</load-on-startup>  
    25.     </servlet>  
    26.   
    27.     <!-- Map all requests to the DispatcherServlet for handling -->  
    28.     <servlet-mapping>  
    29.         <servlet-name>springMVC</servlet-name>  
    30.         <url-pattern>*.action</url-pattern>  
    31.     </servlet-mapping>  
    32. </web-app>  



     

    页面部分(两个jsp页面):

    index.jsp

     

    [html] view plain copy
     
    1. <%@ page language="java" contentType="text/html; charset=UTF-8"  
    2.     pageEncoding="UTF-8"%>  
    3. <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">  
    4. <html>  
    5. <head>  
    6. <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">  
    7. <title>Insert title here</title>  
    8. </head>  
    9. <body>  
    10.     <jsp:forward page="/user/findAll.action"></jsp:forward>  
    11. </body>  
    12. </html>  


    userlist.jsp

     

    [html] view plain copy
     
    1. <%@ page language="java" contentType="text/html; charset=UTF-8"  
    2.     pageEncoding="UTF-8"%>  
    3. <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>  
    4. <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">  
    5. <html>  
    6. <head>  
    7. <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">  
    8. <title>Insert title here</title>  
    9.   
    10. <style type="text/css">  
    11.     #span {  
    12.         text-align: right;  
    13.         float: right;  
    14.     }  
    15.     a {  
    16.         text-decoration: none;  
    17.     }  
    18. </style>  
    19. </head>  
    20. <body>  
    21.     <div>  
    22.         <span id="span"><a href="${pageContext.request.contextPath}/user/addUser.action">新增</a></span>  
    23.     </div>  
    24.     <table border="1" width="100%">  
    25.         <caption>用户表</caption>  
    26.         <tr>  
    27.             <td>姓名</td>  
    28.             <td>年龄</td>  
    29.             <td>性别</td>  
    30.             <td>薪资</td>  
    31.             <td>部门</td>  
    32.             <td>更改</td>  
    33.         </tr>  
    34.     <c:forEach items="${users}" var="user">  
    35.         <tr>  
    36.             <td>${user.username }</td>  
    37.             <td>${user.age }</td>  
    38.             <td>${user.sex }</td>  
    39.             <td>${user.salary }</td>  
    40.             <td>${user.department }</td>  
    41.             <td><a href="${pageContext.request.contextPath }/user/updateUser.action?id=${user.id}">更改</a></td>  
    42.         </tr>  
    43.     </c:forEach>  
    44.     </table>  
    45. </body>  
    46.   
    47. </html>  

     

     

    业务层之UserService接口

     

    [java] view plain copy
     
    1. package com.qx.service;  
    2.   
    3. import java.util.List;  
    4.   
    5. import com.qx.pojo.User;  
    6.   
    7. public interface UserService {  
    8.   
    9.     public List<User> findAll() throws Exception;  
    10.       
    11.     public void AddUser(User user) throws Exception;  
    12.       
    13.     public void updateUserById(Integer id,String username,int age,String sex) throws Exception;  
    14.       
    15. }  


    业务层之UserServiceImpl

     

    实现事务回滚,1.必须要加@Transactional注解   2. catch块中必须throw个异常出来,是触发事务生效的必要条件

     

    [java] view plain copy
     
    1. package com.qx.service;  
    2.   
    3. import java.util.List;  
    4.   
    5. import org.springframework.beans.factory.annotation.Autowired;  
    6. import org.springframework.stereotype.Service;  
    7. import org.springframework.transaction.annotation.Transactional;  
    8.   
    9. import com.qx.mapper.UserMapper;  
    10. import com.qx.pojo.User;  
    11.   
    12. @Service  
    13. @Transactional  
    14. public class UserServiceImpl implements UserService{  
    15.       
    16.     @Autowired  
    17.     private UserMapper userMapper;  
    18.   
    19.     @Override  
    20.     public List<User> findAll() {  
    21.         // TODO Auto-generated method stub  
    22.         List<User> users = null;  
    23.         try {  
    24.             users = userMapper.findAll();  
    25.         } catch (Exception e) {  
    26.             // TODO Auto-generated catch block  
    27.             e.printStackTrace();  
    28.         }  
    29.         return users;  
    30.     }  
    31.   
    32.     @Override  
    33.     public void AddUser(User user)  {  
    34.         // TODO Auto-generated method stub  
    35.         try {  
    36.             userMapper.AddUser(user);  
    37.             //int a=6/0;  
    38.         } catch (Exception e) {  
    39.             // TODO Auto-generated catch block  
    40.             e.printStackTrace();  
    41.             throw new RuntimeException("事务回滚了吗");  
    42.         }  
    43.     }  
    44.   
    45.       
    46.     @Override  
    47.     public void updateUserById(Integer id,String username, int age, String sex) {  
    48.         // TODO Auto-generated method stub  
    49.         try {  
    50.             userMapper.updateUserById(id,username, age, sex);  
    51.             int b=10/0;  
    52.         } catch (Exception e) {  
    53.             // TODO Auto-generated catch block  
    54.             e.printStackTrace();  
    55.             throw new RuntimeException("事务回滚了吗");  
    56.         }  
    57.     }  
    58.   
    59. }  



     

    控制层:UserController

     

    [java] view plain copy
     
    1. package com.qx.controller;  
    2.   
    3. import java.util.List;  
    4.   
    5. import org.springframework.beans.factory.annotation.Autowired;  
    6. import org.springframework.stereotype.Controller;  
    7. import org.springframework.web.bind.annotation.RequestMapping;  
    8. import org.springframework.web.servlet.ModelAndView;  
    9.   
    10. import com.qx.pojo.User;  
    11. import com.qx.service.UserService;  
    12.   
    13. @Controller  
    14. @RequestMapping("/user")  
    15. public class UserController {  
    16.       
    17.     @Autowired  
    18.     private UserService userService;  
    19.   
    20.     @RequestMapping("/findAll")  
    21.     public ModelAndView findAll() throws Exception{  
    22.         ModelAndView mv=new ModelAndView();  
    23.         List<User> users = userService.findAll();  
    24.         mv.addObject("users", users);  
    25.         mv.setViewName("/userlist");  
    26.         return mv;  
    27.     }  
    28.       
    29.     @RequestMapping("/addUser")  
    30.     public String addUser(){  
    31.         User user=new User();  
    32.         user.setUsername("郑爽");  
    33.         user.setAge(17);  
    34.         user.setSex("女");  
    35.         user.setSalary(9856.00);  
    36.         user.setDepartment("销售");  
    37.         try {  
    38.             userService.AddUser(user);  
    39.               
    40.               
    41.         } catch (Exception e) {  
    42.             // TODO Auto-generated catch block  
    43.             e.printStackTrace();  
    44.         }  
    45.         return "redirect:/user/findAll.action";  
    46.           
    47.     }  
    48.       
    49.     @RequestMapping("/updateUser")  
    50.     public String updateUser(Integer id){  
    51.           
    52.         try {  
    53.             userService.updateUserById(id, "逗逼姚"22"男");  
    54.         } catch (Exception e) {  
    55.             // TODO Auto-generated catch block  
    56.             e.printStackTrace();  
    57.         }  
    58.         return "redirect:/user/findAll.action";  
    59.     }  
    60.       
    61. }  

     

     

    向tomcat内添加项目,启动tomcat,地址类输入localhostL8080/TestTranSaction 请求结果为

    点击新增可添加一个用户(代码中定义死了,添加的是郑爽),点击更改可更改一个用户(更改后的用户叫逗逼姚,只更改username,age,sex三个字段)

    为了测试事务回滚,特意加了//int a=6/0; 这样的代码来人为制造异常,此时事务是否添加上了(看是否回滚).可根据需要自行注释或解除注释.

     

     

    归纳点:

    要想事务配置成功:

    1, 要在applicationContext-tran.xml配置文件中 添加事务的注解驱动,必须要有.

    这几项缺一不可.(提醒: 声明式事务是基于AOP的)

    2. 在业务层业务实现类必须要加@Transaction注解

    3. 在业务层业务实现类catch块中必须要throw一个异常,以便触发回滚(这是触发回滚的一个条件)

    4. spring-MVC.xml中要扫具体包只扫到Controller, 因为spring-MVC.xml是输入dispatcherServlet的,而applicationContext.xml,applicationContext-tran.xml是输入contextLoaderListener的, 因此spring-MVC.xml的加载要晚于它俩,会造成本已增加过的方法被覆盖

     

    以上四点缺一不可.

     

    常见的误解:

    显示有增加标记的就一定配置事务成功了.没显示增加比较的说明事务没配置成功.

     

    这个思维完全是荒谬的.

    比如我的spring,springdao(她俩合在一个配置文件applicationContext.xml里面了)和事务tran是分开配置的.(其实spring,springdao也能拆开配置).,事务的配置文件中就没显示增强标记,它深圳还报了一个警告,下图中黄色区域 说Multiple annotations found at this line:- Referenced bean 'dataSource' not   其实这个警告说dataSource未找到,完全不靠谱(我其实在springContext.xml文件中配置过了),就像增加标记不靠谱一样

     

    这个增加标记长什么样呢?在上面这个配置文件中加一行代码就会出现了

    实际上<context:component-scan base-package="xxxx"/>并不是随便就能写的,  只有满足了前面提到的4点,声明式事务才能生效

     

     

     

    扩展知识:

     

    spring事务回滚规则

     

         指示spring事务管理器回滚一个事务的推荐方法是在当前事务的上下文内抛出异常。spring事务管理器会捕捉任何未处理的异常,然后依据规则决定是否回滚抛出异常的事务。

            默认配置下,spring只有在抛出的异常为运行时unchecked异常时才回滚该事务,也就是抛出的异常为RuntimeException的子类(Errors也会导致事务回滚),而抛出checked异常则不会导致事务回滚。可以明确的配置在抛出那些异常时回滚事务,包括checked异常。也可以明确定义那些异常抛出时不回滚事务。还可以编程性的通过setRollbackOnly()方法来指示一个事务必须回滚,在调用完setRollbackOnly()后你所能执行的唯一操作就是回滚。

     

     

     

    事务只读属性

     

          只读事务用于客户代码只读但不修改数据的情形,只读事务用于特定情景下的优化,比如使用Hibernate的时候。
    默认为读写事务。

     

     

            “只读事务”并不是一个强制选项,它只是一个“暗示”,提示数据库驱动程序和数据库系统,这个事务并不包含更改数据的操作,那么JDBC驱动程序和数据库就有可能根据这种情况对该事务进行一些特定的优化,比方说不安排相应的数据库锁,以减轻事务对数据库的压力,毕竟事务也是要消耗数据库的资源的。 

    但是你非要在“只读事务”里面修改数据,也并非不可以,只不过对于数据一致性的保护不像“读写事务”那样保险而已。 

    因此,“只读事务”仅仅是一个性能优化的推荐配置而已,并非强制你要这样做不可

     

     

     

     

    mybatis在写mapper.xml文件时,如何解决参数类型只能传一个的问题?update语句怎么写?

    这两个问题,见mapper接口文件和mapper.xml文件中的写法或说明.

    还是写在这吧:

     

    [java] view plain copy
     
    1. //更改用户  
    2. public void updateUserById(@Param("id") Integer id,@Param("username") String name,  
    3.         @Param("age") Integer age,@Param("sex") String sex) throws Exception;  

     

    [html] view plain copy
     
    1. <!-- 我直接在mapper接口中使用了mybatis的参数注解@Param, 在这里就不用在指明参数类型了-->  
    2. <!-- 即使你想指明也无法直接指明,因为参数类型只接收一个参数,无法接收多个,@Param就是解决这个问题的 -->  
    3. <select id="updateUserById">  
    4.     update user set username=#{username},age=#{age},sex=#{sex} where id=#{id}  
    5. </select>  



     

     

    mysql删除末尾数据后,再插入新数据id不连续解决方案

     

     

     

    MySQL的user表中本来15条数据,我把后5条给删除了,再插入新用户后id会从16开始计数, 导致重新插入值,字段id取值不连续.

     

     

     

    ALTER TABLE USER AUTO_INCREMENT=10;  (此处10改为自己的断点即可)

    代码示例

    首先是数据库表:

    包括book(isbn, book_name, price),account(username, balance),book_stock(isbn, stock)

    然后是使用的类:

    BookShopDao

    复制代码 代码如下:

    package com.yl.spring.tx;

    public interface BookShopDao {
        //根据书号获取书的单价
        public int findBookPriceByIsbn(String isbn);
        //更新书的库存,使书号对应的库存-1
        public void updateBookStock(String isbn);
        //更新用户的账户余额:使username的balcance-price
        public void updateUserAccount(String username, int price);
       
    }

    BookShopDaoImpl

    复制代码 代码如下:

    package com.yl.spring.tx;

    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.jdbc.core.JdbcTemplate;
    import org.springframework.stereotype.Repository;

    @Repository("bookShopDao")
    public class BookShopDaoImpl implements BookShopDao {

        @Autowired
        private JdbcTemplate JdbcTemplate;
       
        @Override
        public int findBookPriceByIsbn(String isbn) {
            String sql = "SELECT price FROM book WHERE isbn = ?";
           
            return JdbcTemplate.queryForObject(sql, Integer.class, isbn);
        }

        @Override
        public void updateBookStock(String isbn) {
            //检查书的库存是否足够,若不够,则抛出异常
            String sql2 = "SELECT stock FROM book_stock WHERE isbn = ?";
            int stock = JdbcTemplate.queryForObject(sql2, Integer.class, isbn);
            if (stock == 0) {
                throw new BookStockException("库存不足!");
            }
            String sql = "UPDATE book_stock SET stock = stock - 1 WHERE isbn = ?";
            JdbcTemplate.update(sql, isbn);
        }

        @Override
        public void updateUserAccount(String username, int price) {
            //检查余额是否不足,若不足,则抛出异常
            String sql2 = "SELECT balance FROM account WHERE username = ?";
            int balance = JdbcTemplate.queryForObject(sql2, Integer.class, username);
            if (balance < price) {
                throw new UserAccountException("余额不足!");
            }       
            String sql = "UPDATE account SET balance = balance - ? WHERE username = ?";
            JdbcTemplate.update(sql, price, username);
        }

    }

    BookShopService

    复制代码 代码如下:
    package com.yl.spring.tx;
    public interface BookShopService {
         public void purchase(String username, String isbn);
    }

    BookShopServiceImpl

    复制代码 代码如下:

    package com.yl.spring.tx;

    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;
    import org.springframework.transaction.annotation.Isolation;
    import org.springframework.transaction.annotation.Propagation;
    import org.springframework.transaction.annotation.Transactional;

    @Service("bookShopService")
    public class BookShopServiceImpl implements BookShopService {

        @Autowired
        private BookShopDao bookShopDao;
       
        /**
         * 1.添加事务注解
         * 使用propagation 指定事务的传播行为,即当前的事务方法被另外一个事务方法调用时如何使用事务。
         * 默认取值为REQUIRED,即使用调用方法的事务
         * REQUIRES_NEW:使用自己的事务,调用的事务方法的事务被挂起。
         *
         * 2.使用isolation 指定事务的隔离级别,最常用的取值为READ_COMMITTED
         * 3.默认情况下 Spring 的声明式事务对所有的运行时异常进行回滚,也可以通过对应的属性进行设置。通常情况下,默认值即可。
         * 4.使用readOnly 指定事务是否为只读。 表示这个事务只读取数据但不更新数据,这样可以帮助数据库引擎优化事务。若真的是一个只读取数据库值得方法,应设置readOnly=true
         * 5.使用timeOut 指定强制回滚之前事务可以占用的时间。
         */
        @Transactional(propagation=Propagation.REQUIRES_NEW,
                isolation=Isolation.READ_COMMITTED,
                noRollbackFor={UserAccountException.class},
                readOnly=true, timeout=3)
        @Override
        public void purchase(String username, String isbn) {
            //1.获取书的单价
            int price = bookShopDao.findBookPriceByIsbn(isbn);
            //2.更新书的库存
            bookShopDao.updateBookStock(isbn);
            //3.更新用户余额
            bookShopDao.updateUserAccount(username, price);;
        }
    }

    BookStockException

    复制代码 代码如下:

    package com.yl.spring.tx;
    public class BookStockException extends RuntimeException {

        /**
         *
         */
        private static final long serialVersionUID = 1L;

        public BookStockException() {
            super();
            // TODO Auto-generated constructor stub
        }

        public BookStockException(String arg0, Throwable arg1, boolean arg2,
                boolean arg3) {
            super(arg0, arg1, arg2, arg3);
            // TODO Auto-generated constructor stub
        }

        public BookStockException(String arg0, Throwable arg1) {
            super(arg0, arg1);
            // TODO Auto-generated constructor stub
        }

        public BookStockException(String arg0) {
            super(arg0);
            // TODO Auto-generated constructor stub
        }

        public BookStockException(Throwable arg0) {
            super(arg0);
            // TODO Auto-generated constructor stub
        }
    }

    UserAccountException

    复制代码 代码如下:

    package com.yl.spring.tx;
    public class UserAccountException extends RuntimeException {

        /**
         *
         */
        private static final long serialVersionUID = 1L;

        public UserAccountException() {
            super();
            // TODO Auto-generated constructor stub
        }

        public UserAccountException(String arg0, Throwable arg1, boolean arg2,
                boolean arg3) {
            super(arg0, arg1, arg2, arg3);
            // TODO Auto-generated constructor stub
        }

        public UserAccountException(String arg0, Throwable arg1) {
            super(arg0, arg1);
            // TODO Auto-generated constructor stub
        }

        public UserAccountException(String arg0) {
            super(arg0);
            // TODO Auto-generated constructor stub
        }

        public UserAccountException(Throwable arg0) {
            super(arg0);
            // TODO Auto-generated constructor stub
        }
    }

    Cashier

    复制代码 代码如下:

    package com.yl.spring.tx;
    import java.util.List;
    public interface Cashier {
        public void checkout(String username, List<String>isbns);
    }

    CashierImpl。CashierImpl.checkout和bookShopService.purchase联合测试了事务的传播行为

    复制代码 代码如下:

    package com.yl.spring.tx;

    import java.util.List;

    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;
    import org.springframework.transaction.annotation.Transactional;

    @Service("cashier")
    public class CashierImpl implements Cashier {
        @Autowired
        private BookShopService bookShopService;
       
        @Transactional
        @Override
        public void checkout(String username, List<String> isbns) {
            for(String isbn : isbns) {
                bookShopService.purchase(username, isbn);
            }
        }
    }

    测试类:

    复制代码 代码如下:

    package com.yl.spring.tx;

    import java.util.Arrays;

    import org.junit.Test;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;

    public class SpringTransitionTest {
       
        private ApplicationContext ctx = null;
        private BookShopDao bookShopDao = null;
        private BookShopService bookShopService = null;
        private Cashier cashier = null;
        {
            ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
            bookShopDao = ctx.getBean(BookShopDao.class);
            bookShopService = ctx.getBean(BookShopService.class);
            cashier = ctx.getBean(Cashier.class);
        }
       
        @Test
        public void testBookShopDaoFindPriceByIsbn() {
            System.out.println(bookShopDao.findBookPriceByIsbn("1001"));
        }

        @Test
        public void testBookShopDaoUpdateBookStock(){
            bookShopDao.updateBookStock("1001");
        }
       
        @Test
        public void testBookShopDaoUpdateUserAccount(){
            bookShopDao.updateUserAccount("AA", 100);
        }
        @Test
        public void testBookShopService(){
            bookShopService.purchase("AA", "1001");
        }
       
        @Test
        public void testTransactionPropagation(){
            cashier.checkout("AA", Arrays.asList("1001", "1002"));
        }
    }

    9. Tomcat: 项目中对tomcat进行优化么. 怎么优化?

    10. 项目中怎么处理的请求和响应乱码问题?

    11. Cooksession 在项目中怎么用的?

    12. Filter过滤器学习的时候用到过滤getpost编码, 自动登录.  项目中用在哪了

    13. Listener监听器学习的时候用来查询数据库监听过生日的人发送邮件.  项目中用在哪了?

    14. Redis用到了么  用于缓存什么信息?

     

     

    Tomcat 底层是serverSocket  自己封装了request reponse  调用了我们的servelt传入request,response  做了请求和响应内容

    在实际项目中,我们往往需要动态生成树形结构的菜单来实现数据的管理,如图1所示;或者是需要动态生成树形的图表结构,如图2所示。这些树形结构往往没有层级限制。

     

    图1 树形菜单结构

     

    树形图表结构

    在此,以图2为例提出问题及解决方案。

    数据库设计:

    列名

    类型

    是否为空

    备注

    Id

    bigint

    编号,主键

    ItemName

    varchar(50)

    子项名称

    StartTime

    datetime

    开始时间

    EndTime

    datetime

    结束时间

    FartherCode

    varchar(50)

    父节点编码,如果值为’0’代表该节点为一级节点

    Code

    varchar(50)

    当前节点编码

    实现:

    (1)读取所有的一级节点,放入DataTable中;

    (2)遍历DataTable的每一行(即DataRow);

    (3)对于给定的DataRow,如果该节点没有根节点,返回对应的字符串,否则,获取该节点的的所有子节点得到DataTable,跳转到第(2)步,最终将所有得到的字符串叠加返回;

    核心算法:

     

    [csharp] view plain copy
     
    1. DataTable dtPlan = ProPlanDao.SelectBySql(base.Conn, "select * from ProPlan where FartherCode='0'"); //获取所有根节点  
    2. string html = string.Empty;  
    3. if (dtPlan.Rows.Count > 0){  
    4.   html += "[";  
    5.   //遍历所有子节点  
    6.   for (int i = 0; i < dtPlan.Rows.Count; i++){  
    7.   html += GetJson(dtPlan.Rows[i]) + ",";}  
    8.   html = html.Substring(0, html.Length - 1) + "]";  
    9. }  
    10. //递归函数  
    11. public string GetJson(DataRow dr){  
    12.   //是否拥有子节点  
    13.   bool hasSon = ProPlanDao.HasSub(base.Conn, Code);  
    14.   //递归出口  
    15.   if (!hasSon){  
    16.   string result = "{"id":" + Id + ",";  
    17.   result += ""rownum":"" + (rowNumber++) + "",";  
    18.   result += ""name":"" + ItemName + "",";  
    19.   result += ""start":"" + StartTime + "",";  
    20.   result += ""end":"" + EndTime + "",";  
    21.        result += ""time":"" + (EndTime - StartTime) + "",";  
    22.        result += ""option":"<a href='#'>添加子任务</a> <a href='#'>编辑</a> <a href='#'>删除</a>"}";  
    23.        return result;  
    24.     }  
    25.   else{  
    26.        DataTable dtSon = ProPlanDao.SelectSub(base.Conn, Code);  
    27.        string result = "{"id":" + Id + ",";  
    28.        result += ""rownum":"" + (rowNumber++) + "",";  
    29.        result += ""name":"" + ItemName + "",";  
    30.        result += ""start":"" + StartTime + "",";  
    31.        result += ""end":"" + EndTime + "",";  
    32.        result += ""time":"" + (EndTime - StartTime) + "",";  
    33.        result += ""option":"<a href='#'>添加子任务</a> <a href='#'>编辑</a> <a href='#'>删除</a>",";  
    34.   result += ""state":"closed",";  
    35.   result += ""children":[";  
    36.   //遍历该节点的所有子节点  
    37.         for (int i = 0; i < dtSon.Rows.Count; i++){  
    38.             result += GetJson(dtSon.Rows[i]) + ",";}  
    39.         result = result.Substring(0, result.Length - 1) + "]}";  
    40.         return result;  
    41.   }  
    42. }  
  • 相关阅读:
    链表_单链表(插入删除查询)
    OceanBase架构浅析(一)
    电商商品搜索现状
    ASP.NET MVC 源码分析(二) —— 从 IRouteBuilder认识路由构建
    ASP.NET MVC 源码分析(一)
    RPC框架分析
    RPC简介
    Performance Metrics(性能指标2)
    Performance Metrics(性能指标1)
    Introduction(本书简介)
  • 原文地址:https://www.cnblogs.com/shan1393/p/9061006.html
Copyright © 2020-2023  润新知