学习SSH框架记录片5----开发简易网上书城

 

============= SSH整合:网上书城 =============

 

1. 配置 Spring

 

    1. 加入 jar 包

    2. 配置web.xml

       1. 配置文件名称和位置

       2. 项目启动监听器,创建 IOC 容器

       3. 注意:<param-name> 配置文件名称必须小写字母开头

           1. 正确:contextConfigLocation

           2. 错误:ContextConfigLocation:找不到 配置文件

    3. 添加applicationContext.xml

 

2. 配置 Hibernate

   

    1. 加入 jar 包

    2. 配置hibernate.cfg.xml 基本信息

    3. 创建实体类,以及映射文件 *.hbm.xml

    4. 整合Spring,配置 applicationContext.xml

       1. 导入context、txaop 的命名空间

       2. 配置 jdbc 基本属性资源文件 db.properties

       3. 导入资源文件

       4. 配置dataSource 的 bean

       5. 配置sessionFactory 的 bean

           1. 配置 dataSource 属性

           2. 配置 hibernate.cfg.xml 属性

           3. 配置 *.hbm.xml 属性

       6. 配置Spring 声明式事务

           1. 配置事务管理器的 bean

           2. 配置事务属性

           3. 配置切点,并和事务关联起来

 

3. 配置 Struts2

   

    1. 加入Struts2 相关 jar 包

    2. 配置web.xml ,过滤器

    3. 加入struts.xml

    4. 整合Spring

       1. 以及和 Spring 关联的 jar 包,去掉和 hibernate 重复的 jar,删较低的版本

       2. 添加新的 Spring 配置文件applicationContext-beans.xml,用于配置 bean

       3. web.xml 中的配置文件名加上通配符

       4. Action 相关的 bean,必须有属性scope="prototype",非单例模式

       5. struts.xml 中配置 Action 时,class 属性直接引用 applicationContext-beans.xml 中相关 bean 的 id

      

4. 实现 Dao 层问题

 

    1.批处理操作

       1. 如果是循环处理的,直接使用 JDBC 的 API

       2. 若使用 Hibernate 自己的批处理,需要控制刷新一级缓存,效率较低

       3. Connection 如何获取?

           1. 定义成员变量 DataSource,类型为 javax.sql.DataSource;

           2. Spring 注入方法,在 baseDao 的 bean 配置时,注入属性 dataSource

           3. 通过 session 的doWork() 方法,保证了事务的统一性,和 spring 声明式事务使用同一个 Connection

       4. 事务如何控制?

    2. 获取泛型对应的具体 Class

       1. 示例:

           public interface BaseDao<T>{}

           public class BaseDaoImpl<T>implements BaseDao<T>{}

           public class BookDaoImpl extendsBaseDaoImpl<Book>, implements BookDao{}

       2. 如果直接测试 BaseDaoImpl 中的方法,则必须保证

           1. public class BaseDaoImpl<T>implements BaseDao<Book>{}

           2. 父类的泛型为具体实体类,否则得到的泛型值仍然是 T,或Object

       3. 获取泛型值得方法

           public class BaseDaoImpl<T>implements BaseDao<T>{

              private Class  entityClass;

              {

                  entityClass =((ParameterizedType)new TestImpl().getClass().getGenericSuperclass())

                         .getActualTypeArguments()[0];

              }

           }

 

5. Spring 相关

   

    1. Spring 配置文件中配置 bean 时,如 Action 的 属性 service,一定要用接口类型   

   

4. Hibernate 相关

   

    1. 若实体类属性为基本类型,如 int,且数据库中该字段为 null,则session.get(Class,id) 时,抛异常

       1. 异常:不能把 null 通过 setter(int) 注入给 int 型属性

       2. 解决:把实体类的字段换成对象,如 Integer、Float 等

    2. 实体映射关系

       1. 双向 n-1

           1. 涉及层级关系时,通过 1 的一端,直接获取 n 的一端数据,便于在把数据返回页面

           2. 如果层级超过 2 层

              1. 第一层直接 A a left join fetch a.b(迫切左外连接)查询

              2. 后面的层次,可依次根据 b 的 id 查询出 c 的集合,再注入到 b 的属性中

           3. 实例:用户和交易记录的关系

           4. 实现

              1. 1 的一端

                  <setname="trades" table="TRADES" inverse="true"order-by="TRADE_TIME desc">

                     <keycolumn="USER_ID"/>

                     <one-to-manyclass="Trade"/>

                  </set>

              2. n 的一端

                  <many-to-onename="user" class="User" column="USER_ID"/>

       2. 单向 n-1

           1. 用的较少,除非 1 的一端不需要访问多的一端数据

           2. 实例:人和地址

           3. 实现

              1. n 的一端

                  <many-to-one name="address"class="Address" column="ADDRESS_ID"/>

              2. 1 的一端不需要任何设置

       3. 单向 1-1

           1. 用<many-to-one unique="true"> 实现

           2. 在有外键的那个表中,必须保证主键和外键都是唯一的

              1. 否则报错:Duplicate entry '1' for key'UK_sty8kglleqd7f8w5qdwpyn9ds'

       4. 双向 n-n

           1. 必须用关联表实现,两边都指定关联表

    3. 批处理 insert 操作

       1. 用 JDBC,若主键生成策略是自增,则失败,因为主键必须保存提交后,才能获取下一个

       2. 用session.save()

           1. spring 声明式事务之内,session.save() 操作只会写入 hibernate 缓存

           2. 如果保存的数量过大,需要及时提交,写入数据库,用 session.flush() 和session.clear()

           3. 否则缓存溢出

           4. 示例:

              for(inti=0; i<list.size(); i++) {

                  save(list.get(i));

                  if((i+1) % 50 == 0) {

                     getSession().flush();

                     getSession().clear();

                  }

              }

       3. 事务中嵌套 JDBC 批处理操作

           1. 如 service 用了Spring 声明式事务,其中某个方法又调用了 jdbc 的批处理操作

           2. 单独的 jdbc 批处理时

              1. 默认 conn.setAutoCommit(false),即开启事务,这样保证不是每个 sql 语句提交一次,而是整体提交

              2. 必须 conn.commit() 或者conn.rollback(),否则,事务不会关闭,很可能锁表

              3、可变参数,用 Object[] 来传递

                  1、二维数字貌似不行,不要直接定义二维数组变量

                  2、若是多维的参数,可用:

                     Object [] objs = new Object[ size ];

                     List<Object> list =new ArrayList<>();

                     objs[i]= list;  

                     //或者 objs[i] = new Object[,,,]

             

           3. Hibernate通过封装 Connection 实现事务功能,开启事务之前,默认 setAutoCommit(false)

           4. 通过 doWork() 的到的 Connection 和session 是同一个

              1. 如果嵌套的 jdbc 批处理中setAutoCommit(false),则 session的事务将失效

              2. 如果嵌套的 jdbc 批处理中commit(),则该嵌套操作不受 service 的事务控制,

                  即后面发生异常,这里提交的也不回滚。

              3. 不需要 setAutoCommit(true),同样不需要 rollback(),让它受控于 service 事务即可。

              4. 可能的问题:

                  1. 比如批处理更新操作,数量不能太大,否则缓存满了就麻烦了

                  2. 就购物车而言,一次购买不会涉及过多的商品种类,所以结账 checkout 操作可以全部放一个事务中。

                  3. 如果确实存在这样的业务:特殊出来一下,单独提供一个 service 方法,只对应一个普通的批处理操作,

                     再访问这个 service 方法即可。

           5. 代码示例:

              getSession().doWork(new Work() {

                  @Override

                  public void execute(Connectionconn) throws SQLException {

                     PreparedStatement pstmt = null;

                     try {

                         pstmt = conn.prepareStatement(sql);

                  //     conn.setAutoCommit(false);

                         if(objects != null) {

                            for(int i=0; i<objects.length; i++) {

                                List<Object>params = (List<Object>)objects[i];

                                if(params != null) {

                                   for(int j=0; j<params.size(); j++) {

                                       pstmt.setObject(j+ 1, params.get(j));

                                   }

                                }

                                pstmt.addBatch();

                                if((i+1) % 100== 0) {

                                   pstmt.executeBatch();

                  //                conn.commit();

                                }

                            }

                         }

                         pstmt.executeBatch();

                  //     conn.commit();

                  //     conn.setAutoCommit(true);

                     } catch (SQLException e) {

                         e.printStackTrace();

                  //     try {

                  //         conn.rollback();

                  //     } catch(Exception e2) {

                  //         e2.printStackTrace();

                  //     }

                     } finally {

                         close(pstmt);

                  //         close(conn);

                     }

                  }

              });

 

 

6. struts2 页面配置

 

    1. 把 Page 对象通过 <s:push> 标签放入栈顶后,调用方法时,值栈自动处理了

       1. getTotalPageNumber(),改成了属性:totalPageNumber,直接访问:${totalPageNumber} 即可

       2. isHasNext(),改成了属性:hasNext,直接访问:${hasNext}

      

    2. 隐藏域重用时,可把公共 jsjsp 代码放一个 jsp 页面中

       1. 加入公共 jsp 页面:<%@ include file="/common/***.jsp" %>

       2. 放在</head> 之前即可

      

    3. 购物车,放 session 中,让 Action 类实现 SessionAware 接口即可得到 sessionMap

   

    4. 带参数的请求,重定向到 Action

       1. <paramname="location"> actionName </param>用来指定 Action

       2. <param name="pageNo">${pageNo} </param> 用来指定参数

       3. 示例

           <result name="addToCart"type="redirect">

              <paramname="location">book-list</param>

              <paramname="pageNo">${pageNo}</param>

              <paramname="minPrice">${minPrice}</param>

              <paramname="maxPrice">${maxPrice}</param>

           </result>

   

    5. 加入外部 javascript 资源时,要使用绝对路径

       1. 通过<%=request.getContextPath()%> 获得根路径

       2. 示例:

           <script type="text/javascript" src="<%=request.getContextPath()%>/scripts/jquery-1.8.3.min.js"></scirpt>

   

    6. jsp页面应该放在 WEB-INF 目录下

       1. 该目录下的 jsp 页面只能通过 action 的方式访问   

       2. jsp页面是带有动态数据的页面,本就不允许直接在前端访问的,而应该先访问控制器,再由控制器返回对应的 jsp 页面

       3. 像错误页面这种提示性的,可以直接放在 Web 根目录下,因为没有动态参数

      

    7. web.xml 中配置参数,并获取值,过滤器中编码转换配置示例:

       1. web.xml 中配置

           <context-param>

              <param-name>encoding</param-name>

              <param-value>UTF-8</param-value>

           </context-param>

       2. 取值,在过滤器 Filter 的 init(FilterConfig fConfig) 方法中获取 FilterConfig

           FilterConfig filterConfig = fConfig;

           String encoding =filterConfig.getServletContext().getInitParameter("encoding");

           request.setCharacterEncoding(encoding);

          

    8. Action 返回  JSON 格式数据

       1. 加入struts2-json-plugin-2.3.32.jar 包

       2. struts.xml 中的 package 的 extends="json-default",实际上该包的 extends="struts-default"

       3. result 格式,其中 name="root" 可以指定 Action 中的某个属性作为 json 返回值

           <result name="***"type="json">

              <paramname="root">jsonMap</param>

           </result>

       4. jsonMap 作为 Action 的成员变量,一定是 Map 类型的

       5. 若不指定 <param name="root"> ,则把整个 Action 视为 json 来返回

   

    9. 表单重复提交

       1. 只限于表单重复提交

       2. 必须在 <form> 内添加<s:token/> 标签

       3. struts.xml 中添加拦截器

           1. 用 token 拦截器:<interceptor-ref name="token" />,必须添加 <resultname="invalid.token">**.jsp</result>

           2. 用 tokenSession 拦截器:<interceptor-refname="tokenSesson" />,不需要额外页面

           3. 示例:

              <actionname="tokenSimple" class="**" method="**">

                  <interceptor-ref name="token" />

                  <interceptor-ref name="basicStack" />

                  <resultname="invalid.token">error.jsp</result>

              </action>

       4. 要单独使用 Action 类

           1. 凡是用了 token 拦截器的 action 请求,必须有 <form><s:token></form> 标签

           2. 其他没在 <form> 内的,或者没有添加 <s:token/> 的请求都会转到 invalid.token 对应的页面

   

    10. 默认Action:在 <package> 包中加入 <default-action-refname="actionName"/> 子标签即可

   

    11. 多个 struts配置文件

       1. 只需struts.xml 包含默认 Action 标签即可

       2. 通过<inclue file="example.xml"/> 包含其他 struts 配置文件即可

       3. Action 数量较多时,便于管理

      

    12. 异常处理

       1. 在struts.xml 配置文件中的 <package> 标签内添加异常处理标签

       2. 全局异常:

           <global-results>

              <resultname="error">error.jsp</result>

              <result name="login"type="redirect">LoginAction</result>

           </global-results>

          

           <global-exception-mappings>

              <exception-mappingexception="java.lang.Exception" result="error" />

              <exception-mappingexception="java.sql.SQLException" result="sqlException"/>

           </global-exception-mappings>

       3. Action 内部异常

           <action name="**">

              <exception-mappingexception="com.**.LoginExcetion"result="login" />

              <resultname="sqlException"type="chain">SQLExceptionAction</result>

           </action>

       4. 全局异常只能捕获类似 execute 的action 方法抛出的异常,而不能捕获构造方法抛出的异常。

       5. 匹配异常,以及匹配 result 时,都是按局部到全局的顺序。

       6. 自定义异常,继承 Exception 类,使用方法同系统异常。

      

    13. 相对路径

       1. 用<base href=""> 标签指定绝对路径:

           <base href="${pageContext.request.scheme}://${pageContext.request.serverName}:${pageContext.request.serverPort}${pageContext.request.contextPath}/">

       2. 应将<base> 标签和 <taglib> 标签放到一个common.jsp 中

           <%@ page language="java"contentType="text/html; charset=UTF-8"pageEncoding="UTF-8"%>

           <%@ taglibprefix="s" uri="/struts-tags"%>

           <base href="${pageContext.request.scheme}://${pageContext.request.serverName }:${pageContext.request.serverPort}${pageContext.request.contextPath }/">

       3. 在其他页面中包含该 jsp,其中 commons 目录要放在根目录下,即WebContent 下

           <%@ includefile="/commons/common.jsp" %>

          

    14. 拦截器

       1. 自定义拦截器,要继承 AbstractInterceptor 类,并实现方法 public String intercept(ActionInvocation invocation)

       2. 获取 url 参数:

           ActionContext ac = invocation.getInvocationContext();

            finalMap<String, Object> parameters = ac.getParameters()

        3. 其中,parameters 的 value 是 String [] 类型的

        4. 示例:去掉空格

             for(String key : parameters.keySet()) {

             String[] arrStr = (String[])parameters.get(key);

             for(inti=0; i<arrStr.length; i++) {

                if(arrStr[i] != null)

                    arrStr[i] = arrStr[i].trim();                 

                }

            }

       5. 最后,一定要返回拦截器栈:return invocation.invoke();

            

     

      

           

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值