javaweb学习笔记

  • 1. servlet-api
    • 1.1 servlet初始化
    • 1.2 ServletContext和context-param
  • 2. 什么是业务层
  • 3. IOC
    • 3.1 耦合/依赖
    • 3.2 IOC - 控制反转 / DI - 依赖注入
  • 4.Filter
    • 4.1 增加Filter-设置编码
  • 5. 事务管理
    • 5.1 编程式事务管理
    • 5.2 Threadlocal
    • 5.3 事务管理的实现
    • 问题:DAO报错但是事务没有回滚
  • 6. 监听器Listener
    • 6.1 ServletContextListener的应用 - ContextLoaderListener
  • review

代码重工

1. servlet-api

servlet生命周期: 实例化、初始化、服务、销毁

1.1 servlet初始化

Servlet中的初始化方法有两个:init() , init(config)
其中带参数的方法代码如下:

   public void init(ServletConfig config) throws ServletException {this.config = config ;init();}

另外一个无参的init方法如下:

 public void init() throws ServletException{}

如果我们想要在Servlet初始化时做一些准备工作,那么我们可以重写init方法
我们可以通过如下步骤去获取初始化设置的数据

  • 获取config对象:ServletConfig config = getServletConfig();
  • 获取初始化参数值: config.getInitParameter(key);

在web.xml文件中配置Servlet初始化参数

<servlet><servlet-name>Demo01Servlet</servlet-name><servlet-class>com.atguigu.servlet.Demo01Servlet</servlet-class><init-param><param-name>hello</param-name><param-value>world</param-value></init-param><init-param><param-name>uname</param-name><param-value>jim</param-value></init-param>
</servlet>
<servlet-mapping><servlet-name>Demo01Servlet</servlet-name><url-pattern>/demo01</url-pattern>
</servlet-mapping>

也可以通过注解的方式进行配置

 @WebServlet(urlPatterns = {"/demo01"} ,initParams = {@WebInitParam(name="hello",value="world"),@WebInitParam(name="uname",value="jim")})

1.2 ServletContext和context-param

context就是application(servletContext),多个用户可以共享这个值

  1. 获取ServletContext,有很多方法
    在初始化方法中: ServletContxt servletContext = getServletContext();
    在服务方法中也可以通过request对象获取,也可以通过session获取:
    request.getServletContext(); session.getServletContext()
  2. 获取初始化值:
    servletContext.getInitParameter();

2. 什么是业务层

MVC:经典的架构模式

Model1和Model2
MVC : Model(模型)、View(视图)、Controller(控制器)
视图层:用于做数据展示以及和用户交互的一个界面
控制层:能够接受客户端的请求,具体的业务功能还是需要借助于模型组件来完成
模型层:模型分为很多种:有比较简单的pojo/vo(value object),有业务模型组件,有数据访问层组件
1) pojo/vo : 值对象
2) DAO : 数据访问对象
3) BO : 业务对象

区分业务对象和数据访问对象:
1) DAO中的方法都是单精度方法或者称之为细粒度方法。什么叫单精度?一个方法只考虑一个操作,比如添加,那就是insert操作、查询那就是select操作…

2) BO中的方法属于业务方法,也实际的业务是比较复杂的,因此业务方法的粒度是比较粗的
注册这个功能属于业务功能,也就是说注册这个方法属于业务方法。
那么这个业务方法中包含了多个DAO方法。也就是说注册这个业务功能需要通过多个DAO方法的组合调用,从而完成注册功能的开发。
注册:
1. 检查用户名是否已经被注册 - DAO中的select操作
2. 向用户表新增一条新用户记录 - DAO中的insert操作
3. 向用户积分表新增一条记录(新用户默认初始化积分100分) - DAO中的insert操作
4. 向系统消息表新增一条记录(某某某新用户注册了,需要根据通讯录信息向他的联系人推送消息) - DAO中的insert操作
5. 向系统日志表新增一条记录(某用户在某IP在某年某月某日某时某分某秒某毫秒注册) - DAO中的insert操作
6. …
3) 在库存系统中添加业务层组件

添加service层

package com.atguigu.fruit.service;import com.atguigu.fruit.pojo.Fruit;import java.util.List;public interface FruitService {//获取指定页面的库存列表信息List<Fruit> getFruitList(String keyword , Integer pageNo);//添加库存记录信息void addFruit(Fruit fruit);//根据id查看指定库存记录Fruit getFruitByFid(Integer fid);//删除特定库存记录void delFruit(Integer fid);//获取总页数Integer getPageCount(String keyword);//修改特定库存记录void updateFruit(Fruit fruit);
}

3. IOC

3.1 耦合/依赖

依赖指的是某某某离不开某某某
在软件系统中,层与层之间是存在依赖的。我们也称之为耦合。
我们系统架构或者是设计的一个原则是: 高内聚低耦合。
层内部的组成应该是高度聚合的,而层与层之间的关系应该是低耦合的,最理想的情况0耦合(就是没有耦合)

步骤:
将服务层的FruitServiceImpl的
private FruitDAO fruitDAO = new FruitDAOImpl;
改为
private FruitDAO fruitDAO = null ;

FruitController中
private FruitService fruitService = new FruitServiceImpl ;
也改成
private FruitService fruitService = null ;

怎么解决空指针问题?
通过配置i文件,标签,组件。
在启动的时候,会将这三个组件准备好,放在容器里面。谁想要就主动给谁。

<beans><bean id="fruitDAO" class="com.atguigu.fruit.dao.impl.FruitDAOImpl"/><bean id="fruitService" class="com.atguigu.fruit.service.impl.FruitServiceImpl"><!-- property标签用来表示属性;name表示属性名;ref表示引用其他bean的id值--><property name="fruitDAO" ref="fruitDAO"/></bean><bean id="fruit" class="com.atguigu.fruit.controllers.FruitController"><property name="fruitService" ref="fruitService"/></bean>
</beans>
<!--
Node 节点Element 元素节点Text 文本节点
<sname>jim</sname>
-->

定义一个获取bean对象的接口,需要一个map容器

package com.atguigu.myssm.io;public interface BeanFactory {Object getBean(String id);
}

实现这个接口

package com.atguigu.myssm.io;import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;public class ClassPathXmlApplicationContext implements BeanFactory {private Map<String,Object> beanMap = new HashMap<>();public ClassPathXmlApplicationContext(){try {InputStream inputStream = getClass().getClassLoader().getResourceAsStream("applicationContext.xml");//1.创建DocumentBuilderFactoryDocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();//2.创建DocumentBuilder对象DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder() ;//3.创建Document对象Document document = documentBuilder.parse(inputStream);//4.获取所有的bean节点NodeList beanNodeList = document.getElementsByTagName("bean");for(int i = 0 ; i<beanNodeList.getLength() ; i++){Node beanNode = beanNodeList.item(i);if(beanNode.getNodeType() == Node.ELEMENT_NODE){Element beanElement = (Element)beanNode ;String beanId =  beanElement.getAttribute("id");String className = beanElement.getAttribute("class");Class beanClass = Class.forName(className);//创建bean实例Object beanObj = beanClass.newInstance() ;//将bean实例对象保存到map容器中beanMap.put(beanId , beanObj) ;//到目前为止,此处需要注意的是,bean和bean之间的依赖关系还没有设置}}//5.组装bean之间的依赖关系for(int i = 0 ; i<beanNodeList.getLength() ; i++){Node beanNode = beanNodeList.item(i);if(beanNode.getNodeType() == Node.ELEMENT_NODE) {Element beanElement = (Element) beanNode;String beanId = beanElement.getAttribute("id");NodeList beanChildNodeList = beanElement.getChildNodes();for (int j = 0; j < beanChildNodeList.getLength() ; j++) {Node beanChildNode = beanChildNodeList.item(j);if(beanChildNode.getNodeType()==Node.ELEMENT_NODE && "property".equals(beanChildNode.getNodeName())){Element propertyElement = (Element) beanChildNode;String propertyName = propertyElement.getAttribute("name");String propertyRef = propertyElement.getAttribute("ref");//1) 找到propertyRef对应的实例Object refObj = beanMap.get(propertyRef);//2) 将refObj设置到当前bean对应的实例的property属性上去Object beanObj = beanMap.get(beanId);Class beanClazz = beanObj.getClass();Field propertyField = beanClazz.getDeclaredField(propertyName);propertyField.setAccessible(true);propertyField.set(beanObj,refObj);}}}}} catch (ParserConfigurationException e) {e.printStackTrace();} catch (SAXException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();} catch (IllegalAccessException e) {e.printStackTrace();} catch (InstantiationException e) {e.printStackTrace();} catch (ClassNotFoundException e) {e.printStackTrace();} catch (NoSuchFieldException e) {e.printStackTrace();}}@Overridepublic Object getBean(String id) {return beanMap.get(id);}
}

改动DispatcherServlet,获取beanFactory

public class DispatcherServlet extends ViewBaseServlet{private BeanFactory beanFactory ;public DispatcherServlet(){}public void init() throws ServletException {super.init();beanFactory = new ClassPathXmlApplicationContext();}

在配置文件中

<!-- property标签用来表示属性;name表示属性名;ref表示引用其他bean的id值--><property name="fruitDAO" ref="fruitDAO"/>



48 30:29
在ClassPathXmlApplicationContext中组装bean之间的依赖关系

//5.组装bean之间的依赖关系for(int i = 0 ; i<beanNodeList.getLength() ; i++){Node beanNode = beanNodeList.item(i);if(beanNode.getNodeType() == Node.ELEMENT_NODE) {Element beanElement = (Element) beanNode;String beanId = beanElement.getAttribute("id");NodeList beanChildNodeList = beanElement.getChildNodes();for (int j = 0; j < beanChildNodeList.getLength() ; j++) {Node beanChildNode = beanChildNodeList.item(j);if(beanChildNode.getNodeType()==Node.ELEMENT_NODE && "property".equals(beanChildNode.getNodeName())){Element propertyElement = (Element) beanChildNode;String propertyName = propertyElement.getAttribute("name");String propertyRef = propertyElement.getAttribute("ref");//1) 找到propertyRef对应的实例Object refObj = beanMap.get(propertyRef);//2) 将refObj设置到当前bean对应的实例的property属性上去Object beanObj = beanMap.get(beanId);Class beanClazz = beanObj.getClass();Field propertyField = beanClazz.getDeclaredField(propertyName);propertyField.setAccessible(true);propertyField.set(beanObj,refObj);}}}}

3.2 IOC - 控制反转 / DI - 依赖注入

这就是每层之间都解耦了,但是都依赖ApplicationContext容器,容器又是读取配置文件,所以最终个模块只依赖配置文件的参数。

控制反转:
1) 之前在Servlet中,我们创建service对象 , FruitService fruitService = new FruitServiceImpl();
这句话如果出现在servlet中的某个方法内部,那么这个fruitService的作用域(生命周期)应该就是这个方法级别;
如果这句话出现在servlet的类中,也就是说fruitService是一个成员变量,那么这个fruitService的作用域(生命周期)应该就是这个servlet实例级别
2) 之后我们在applicationContext.xml中定义了这个fruitService。然后通过解析XML,产生fruitService实例,存放在beanMap中,这个beanMap在一个BeanFactory中
因此,我们转移(改变)了之前的service实例、dao实例等等他们的生命周期。控制权从程序员转移到BeanFactory。这个现象我们称之为控制反转

依赖注入:
1) 之前我们在控制层出现代码:FruitService fruitService = new FruitServiceImpl();
那么,控制层和service层存在耦合。
2) 之后,我们将代码修改成FruitService fruitService = null ;
然后,在配置文件中配置:

   <bean id="fruit" class="FruitController"><property name="fruitService" ref="fruitService"/></bean>

依赖注入是IOC的具体实现

4.Filter

  1. Filter也属于Servlet规范
  2. Filter开发步骤:新建类实现Filter接口,然后实现其中的三个方法:init、doFilter、destroy
    配置Filter,可以用注解@WebFilter,也可以使用xml文件 <filter> <filter-mapping>
  3. Filter在配置时,和servlet一样,也可以配置通配符,例如 @WebFilter(“*.do”)表示拦截所有以.do结尾的请求
  4. 过滤器链
    1)执行的顺序依次是: A B C demo03 C2 B2 A2
    2)如果采取的是注解的方式进行配置,那么过滤器链的拦截顺序是按照全类名的先后顺序排序的
    3)如果采取的是xml的方式进行配置,那么按照配置的先后顺序进行排序
package com.atguigu.filters;import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;//@WebFilter("/demo01.do")
@WebFilter("*.do")
public class Demo01Filter implements Filter {@Overridepublic void init(FilterConfig filterConfig) throws ServletException {}@Overridepublic void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {System.out.println("helloA");//放行filterChain.doFilter(servletRequest,servletResponse);System.out.println("helloA2");}@Overridepublic void destroy() {}
}

4.1 增加Filter-设置编码

package com.atguigu.myssm.filters;import com.atguigu.myssm.util.StringUtil;import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.annotation.WebInitParam;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;@WebFilter(urlPatterns = {"*.do"},initParams = {@WebInitParam(name = "encoding",value = "UTF-8")})
public class CharacterEncodingFilter implements Filter {private String encoding = "UTF-8";@Overridepublic void init(FilterConfig filterConfig) throws ServletException {String encodingStr = filterConfig.getInitParameter("encoding");if(StringUtil.isNotEmpty(encodingStr)){encoding = encodingStr ;}}@Overridepublic void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {((HttpServletRequest)servletRequest).setCharacterEncoding(encoding); // 完成设置编码filterChain.doFilter(servletRequest,servletResponse);// 放行}@Overridepublic void destroy() {}
}

5. 事务管理

5.1 编程式事务管理

事务管理的操作不能写在DAO层。
service的操作应该是一个整体,不能部分成功部分失败。
事务管理不能以DAO层的单精度方法为单位,而应该以业务层的方法为单位

解决方法:

进一步利用Filter进行事务管理,

DAO1、2、3这三个组件中的三个操作需要同一个Connection,这样我们才可以让三个操作处于一个事务中。
如何解决?

5.2 Threadlocal

链接
- get() , set(obj)
- ThreadLocal称之为本地线程 。 我们可以通过set方法在当前线程上存储数据、通过get方法在当前线程上获取数据

-set方法源码分析:

 public void set(T value) {Thread t = Thread.currentThread(); //获取当前的线程ThreadLocalMap map = getMap(t);    //每一个线程都维护各自的一个容器(ThreadLocalMap)if (map != null)map.set(this, value);          //这里的key对应的是ThreadLocal,因为我们的组件中需要传输(共享)的对象可能会有多个(不止Connection)elsecreateMap(t, value);           //默认情况下map是没有初始化的,那么第一次往其中添加数据时,会去初始化}

-get方法源码分析:

 public T get() {Thread t = Thread.currentThread(); //获取当前的线程ThreadLocalMap map = getMap(t);    //获取和这个线程(企业)相关的ThreadLocalMap(也就是工作纽带的集合)if (map != null) {ThreadLocalMap.Entry e = map.getEntry(this);   //this指的是ThreadLocal对象,通过它才能知道是哪一个工作纽带if (e != null) {@SuppressWarnings("unchecked")T result = (T)e.value;     //entry.value就可以获取到工具箱了return result;}}return setInitialValue();}

一句话理解ThreadLocal,threadlocl是作为当前线程中属性ThreadLocalMap集合中的某一个Map的key值Map(threadlocl,value),虽然不同的线程之间threadlocal这个key值是一样,但是不同的线程所拥有的ThreadLocalMap是独一无二的,也就是不同的线程间同一个ThreadLocal(key)对应存储的值(value)不一样,从而到达了线程间变量隔离的目的,但是同一个线程中这个变量value是一样的。

同一个线程来实现事务控制

5.3 事务管理的实现

涉及到的组件:
- OpenSessionInViewFilter
- TransactionManager
- ThreadLocal
- ConnUtil
- BaseDAO

com.atguigu.myssm.filters.OpenSessionInViewFilter

将开启事务,提交事务,回滚事务封装成一个类。
com.atguigu.myssm.trans.TransactionManager 将获取到的conn放在Threadlocal里。

connection如何获取?
由com.atguigu.myssm.basedao.ConnUtil获取connection

package com.atguigu.myssm.filters;import com.atguigu.myssm.trans.TransactionManager;import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;
import java.sql.SQLException;@WebFilter("*.do")
public class OpenSessionInViewFilter implements Filter {@Overridepublic void init(FilterConfig filterConfig) throws ServletException {}@Overridepublic void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {try{TransactionManager.beginTrans();System.out.println("开启事务....");filterChain.doFilter(servletRequest, servletResponse);TransactionManager.commit();System.out.println("提交事务...");}catch (Exception e){e.printStackTrace();try {TransactionManager.rollback();System.out.println("回滚事务....");} catch (SQLException ex) {ex.printStackTrace();}}}@Overridepublic void destroy() {}
}
package com.atguigu.myssm.trans;import com.atguigu.myssm.basedao.ConnUtil;import java.sql.Connection;
import java.sql.SQLException;public class TransactionManager {//开启事务public static void beginTrans() throws SQLException {ConnUtil.getConn().setAutoCommit(false);}//提交事务public static void commit() throws SQLException {Connection conn = ConnUtil.getConn();conn.commit();ConnUtil.closeConn();}//回滚事务public static void rollback() throws SQLException {Connection conn = ConnUtil.getConn();conn.rollback();ConnUtil.closeConn();}
}
package com.atguigu.myssm.basedao;import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;public class ConnUtil {private static ThreadLocal<Connection> threadLocal = new ThreadLocal<>();//private static ThreadLocal<Object> threadLocal2 = new ThreadLocal<>();//private static ThreadLocal<Object> threadLocal3 = new ThreadLocal<>();public static final String DRIVER = "com.mysql.jdbc.Driver" ;public static final String URL = "jdbc:mysql://localhost:3306/fruitdb?useUnicode=true&characterEncoding=utf-8&useSSL=false";public static final String USER = "root";public static final String PWD = "123456" ;private static Connection createConn(){try {//1.加载驱动Class.forName(DRIVER);//2.通过驱动管理器获取连接对象return DriverManager.getConnection(URL, USER, PWD);} catch (ClassNotFoundException | SQLException e) {e.printStackTrace();}return null ;}public static Connection getConn(){Connection conn = threadLocal.get();if(conn==null){conn =createConn();threadLocal.set(conn);}return threadLocal.get() ;}public static void closeConn() throws SQLException {Connection conn = threadLocal.get();if(conn==null){return ;}if(!conn.isClosed()){conn.close();threadLocal.set(null);}}
}

问题:DAO报错但是事务没有回滚

链接
因为DAO层的try catch捕捉到了异常。所以filter没有捕捉到异常,没有进行事务回滚。

解决方法:将DAO层的报错都往出抛,按道理要封装出自定义异常,不同的层设计不同的异常

可以捕捉到了以后,抛出自定义异常

package com.atguigu.myssm.basedao;public class DAOException extends RuntimeException{public DAOException(String msg){super(msg);}
}
package com.atguigu.myssm.basedao;import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;public abstract class BaseDAO<T> {protected Connection conn ;protected PreparedStatement psmt ;protected ResultSet rs ;//T的Class对象private Class entityClass ;public BaseDAO() {//getClass() 获取Class对象,当前我们执行的是new FruitDAOImpl() , 创建的是FruitDAOImpl的实例//那么子类构造方法内部首先会调用父类(BaseDAO)的无参构造方法//因此此处的getClass()会被执行,但是getClass获取的是FruitDAOImpl的Class//所以getGenericSuperclass()获取到的是BaseDAO的ClassType genericType = getClass().getGenericSuperclass();//ParameterizedType 参数化类型Type[] actualTypeArguments = ((ParameterizedType) genericType).getActualTypeArguments();//获取到的<T>中的T的真实的类型Type actualType = actualTypeArguments[0];try {entityClass = Class.forName(actualType.getTypeName());} catch (ClassNotFoundException e) {e.printStackTrace();throw new DAOException("BaseDAO 构造方法出错了,可能的原因是没有指定<>中的类型");}}protected Connection getConn(){return ConnUtil.getConn();}protected void close(ResultSet rs , PreparedStatement psmt , Connection conn){}//给预处理命令对象设置参数private void setParams(PreparedStatement psmt , Object... params) throws SQLException {if(params!=null && params.length>0){for (int i = 0; i < params.length; i++) {psmt.setObject(i+1,params[i]);}}}//执行更新,返回影响行数protected int executeUpdate(String sql , Object... params) {boolean insertFlag = false ;insertFlag = sql.trim().toUpperCase().startsWith("INSERT");conn = getConn();try{if(insertFlag){psmt = conn.prepareStatement(sql,Statement.RETURN_GENERATED_KEYS);}else {psmt = conn.prepareStatement(sql);}setParams(psmt,params);int count = psmt.executeUpdate() ;if(insertFlag){rs = psmt.getGeneratedKeys();if(rs.next()){return ((Long)rs.getLong(1)).intValue();}}return 0 ;}catch (SQLException e){e.printStackTrace();throw new DAOException("BaseDAO executeUpdate出错了");}}//通过反射技术给obj对象的property属性赋propertyValue值private void setValue(Object obj ,  String property , Object propertyValue) throws NoSuchFieldException, IllegalAccessException {Class clazz = obj.getClass();//获取property这个字符串对应的属性名 , 比如 "fid"  去找 obj对象中的 fid 属性Field field = clazz.getDeclaredField(property);if(field!=null){field.setAccessible(true);field.set(obj,propertyValue);}}//执行复杂查询,返回例如统计结果protected Object[] executeComplexQuery(String sql , Object... params){conn = getConn() ;try{psmt = conn.prepareStatement(sql);setParams(psmt,params);rs = psmt.executeQuery();//通过rs可以获取结果集的元数据//元数据:描述结果集数据的数据 , 简单讲,就是这个结果集有哪些列,什么类型等等ResultSetMetaData rsmd = rs.getMetaData();//获取结果集的列数int columnCount = rsmd.getColumnCount();Object[] columnValueArr = new Object[columnCount];//6.解析rsif(rs.next()){for(int i = 0 ; i<columnCount;i++){Object columnValue = rs.getObject(i+1);     //33    苹果      5columnValueArr[i]=columnValue;}return columnValueArr ;}}catch(SQLException e){e.printStackTrace();throw new DAOException("BaseDAO executeComplexQuery出错了");}return null ;}//执行查询,返回单个实体对象protected T load(String sql , Object... params){conn = getConn() ;try{psmt = conn.prepareStatement(sql);setParams(psmt,params);rs = psmt.executeQuery();//通过rs可以获取结果集的元数据//元数据:描述结果集数据的数据 , 简单讲,就是这个结果集有哪些列,什么类型等等ResultSetMetaData rsmd = rs.getMetaData();//获取结果集的列数int columnCount = rsmd.getColumnCount();//6.解析rsif(rs.next()){T entity = (T)entityClass.newInstance();for(int i = 0 ; i<columnCount;i++){String columnName = rsmd.getColumnName(i+1);            //fid   fname   priceObject columnValue = rs.getObject(i+1);     //33    苹果      5setValue(entity,columnName,columnValue);}return entity ;}}catch (Exception e){e.printStackTrace();throw new DAOException("BaseDAO load出错了");}return null ;}//执行查询,返回Listprotected List<T> executeQuery(String sql , Object... params){List<T> list = new ArrayList<>();conn = getConn() ;try{psmt = conn.prepareStatement(sql);setParams(psmt,params);rs = psmt.executeQuery();//通过rs可以获取结果集的元数据//元数据:描述结果集数据的数据 , 简单讲,就是这个结果集有哪些列,什么类型等等ResultSetMetaData rsmd = rs.getMetaData();//获取结果集的列数int columnCount = rsmd.getColumnCount();//6.解析rswhile(rs.next()){T entity = (T)entityClass.newInstance();for(int i = 0 ; i<columnCount;i++){String columnName = rsmd.getColumnName(i+1);            //fid   fname   priceObject columnValue = rs.getObject(i+1);     //33    苹果      5setValue(entity,columnName,columnValue);}list.add(entity);}}catch (Exception e){e.printStackTrace();throw new DAOException("BaseDAO executeQuery出错了");}return list ;}
}

6. 监听器Listener

1) ServletContextListener - 监听ServletContext对象的创建和销毁的过程
2) HttpSessionListener - 监听HttpSession对象的创建和销毁的过程
3) ServletRequestListener - 监听ServletRequest对象的创建和销毁的过程4) ServletContextAttributeListener - 监听ServletContext的保存作用域的改动(add,remove,replace)
5) HttpSessionAttributeListener - 监听HttpSession的保存作用域的改动(add,remove,replace)
6) ServletRequestAttributeListener - 监听ServletRequest的保存作用域的改动(add,remove,replace)7) HttpSessionBindingListener - 监听某个对象在Session域中的创建与移除
8) HttpSessionActivationListener - 监听某个对象在Session域中的序列化和反序列化
package com.atguigu.listener;import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;//@WebListener
public class MyServletContextListener implements ServletContextListener {@Overridepublic void contextInitialized(ServletContextEvent servletContextEvent) {System.out.println("Servlet上下文对象初始化动作被我监听到了....");}@Overridepublic void contextDestroyed(ServletContextEvent servletContextEvent) {System.out.println("Servlet上下文对象销毁动作被我监听到了.....");}
}

6.1 ServletContextListener的应用 - ContextLoaderListener

在DispatcherServlet的初始化方法中创建了IOC的beanFactory
最好的情况是当前上下文被启动的时候,IOC的beanFactory就准备就绪。启动性能虽然低,但是响应的性能很高。

移到Listener中

package com.atguigu.myssm.listeners;import com.atguigu.myssm.ioc.BeanFactory;
import com.atguigu.myssm.ioc.ClassPathXmlApplicationContext;import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;//监听上下文启动,在上下文启动的时候去创建IOC容器,然后将其保存到application作用域
//后面中央控制器再从application作用域中去获取IOC容器
@WebListener
public class ContextLoaderListener implements ServletContextListener {@Overridepublic void contextInitialized(ServletContextEvent servletContextEvent) {//1.获取ServletContext对象ServletContext application = servletContextEvent.getServletContext();//2.获取上下文的初始化参数String path = application.getInitParameter("contextConfigLocation");//3.创建IOC容器BeanFactory beanFactory = new ClassPathXmlApplicationContext(path);//4.将IOC容器保存到application作用域application.setAttribute("beanFactory",beanFactory);}@Overridepublic void contextDestroyed(ServletContextEvent servletContextEvent) {}
}

然后在DispatcherServlet 中直接获取ServletContext

@WebServlet("*.do")
public class DispatcherServlet extends ViewBaseServlet{private BeanFactory beanFactory ;public DispatcherServlet(){}public void init() throws ServletException {super.init();//之前是在此处主动创建IOC容器的//现在优化为从application作用域去获取//beanFactory = new ClassPathXmlApplicationContext();ServletContext application = getServletContext();Object beanFactoryObj = application.getAttribute("beanFactory");if(beanFactoryObj!=null){beanFactory = (BeanFactory)beanFactoryObj ;}else{throw new RuntimeException("IOC容器获取失败!");}}

review

链接

【javaweb学习笔记】servlet-api,filter和Listener相关推荐

  1. Javaweb学习笔记 servlet篇

    servlet a)什么是servlet b)手动实现servlet程序 常见的错误: c)url地址到servlet程序的访问 d)servlet的生命周期 e)get和post的分发处理 f)通过 ...

  2. Spring Boot 学习系列(08)—自定义servlet、filter及listener

    此文已由作者易国强授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. 传统的filter及listener配置 在传统的Java web项目中,servlet.filter和li ...

  3. B站狂神说JavaWeb学习笔记

    JavaWeb学习笔记(根据b站狂神说java编写) 1.基本概念 1.1 前言 静态Web: 提供给所有人看数据不会发生变化! HTML,CSS 动态Web: 有数据交互,登录账号密码,网站访问人数 ...

  4. JavaWeb学习笔记(5)-B站尚硅谷

    文章目录 十四.书城项目第三阶段--优化 (1)页面jsp动态化 (2)抽取页面中相同的内容 A.登录成功的菜单 B.base.css.jQuery标签 C.每个页面的页脚 D.manager模块的菜 ...

  5. JavaWeb学习笔记(十)--HttpServletRequest

    1. HttpServletRequest简介 HttpServletRequest对象代表客户端的请求,当客户端通过HTTP协议访问服务器时,HTTP请求头中的所有信息都封装在这个对象中 2. Ht ...

  6. springboot_4 spring boot 使用servlet,filter,listener和interceptor

    上一篇我们学习了 spring boot 利用Controller响应数据与响应页面. 一般的Web开发使用 Controller 基本上可以完成大部分需求,但是有的时候我们还是会用到 Servlet ...

  7. Servlet学习笔记 Servlet原理

    Servlet学习笔记 Servlet原理 一.Servlet基础 1.Servlet执行过程 用户请求一个Servlet,Servlet容器自动构建请求和响应对象,然后执行Servlet的servi ...

  8. filter过滤后重新添加_Spring Boot 2.X(十):自定义注册 Servlet、Filter、Listener

    前言 在 Spring Boot 中已经移除了 web.xml 文件,如果需要注册添加 Servlet.Filter.Listener 为 Spring Bean,在 Spring Boot 中有两种 ...

  9. java手动注册filter,SpringBoot如何注册Servlet、Filter、Listener的几种方式

    在Servlet 3.0之前都是使用web.xml文件进行配置,需要增加Servlet.Filter或者Listener都需要在web.xml增加相应的配置.Servlet 3.0之后可以使用注解进行 ...

最新文章

  1. 理解数据类型与数学运算:求和、温度转换
  2. docker 数据卷 mysql_Docker容器数据卷原理及使用方法解析
  3. 乐在其中设计模式(C#) - 责任链模式(Chain of Responsibility Pattern)
  4. alexnet vgg_从零开始:建立著名的分类网2(AlexNet / VGG)
  5. 一个罐子统治一切:Apache TomEE + Shrinkwrap == JavaEE引导
  6. 手机java做贪吃蛇_如何用Java写一个贪吃蛇游戏
  7. Mac 实用开发工具
  8. java 图片转成base64编码_java语言中如何将一个图片转换为base64编码的数据呢?
  9. 点评2009年PHP十大图书(2)
  10. matlab节约里程法_MATLAB语言基础-中国大学mooc-试题题目及答案
  11. 测试微信好友是否删除软件,如何测试微信好友是否删了你?
  12. Java 线程池常见误区
  13. Java各种学习资源(视频+文档)
  14. oracle客户端12560,windows下 sqlplus / as sysdba 报ora-12560的终极解决方法
  15. 自定义TabLayout
  16. spring整合aspects做aop演示
  17. 数据结构与算法——迷宫问题
  18. idea构建gradle项目报错Could not target platform: ‘Java SE 14‘ using tool chain: ‘JDK 8 (1.8)‘.
  19. 华子20221012笔试第三题
  20. 条码打印出现乱码的解决方案

热门文章

  1. NYOJ1217 GLaDOS的耳机(线段树,区间染色)
  2. 【直播预告】SDWAN+安全,如何帮助企业组建安全智能的自有网络
  3. 计量经济学计算机数据分析,如何用计量经济学作实证分析..doc
  4. N5105 软路由安装 ESXi 7 直通核显给 Debian / Ubuntu 虚拟机通过 Docker 实现 jellyfin 硬件转码视频文件(硬解/编码)
  5. 字符串乘以数字python_将字符串乘以数字!
  6. 用c语言写复化梯形积分公式,第六章 函数和宏定义实验(2)
  7. LeetCode算法,每日一题,冲击阿里巴巴,day7
  8. office软件的发展前景_办公软件未来趋势之七个演变
  9. 【测试沉思录】14. 性能测试中的系统资源分析之一:CPU
  10. mysql备份工具xtr,xtrbackup备份mysql与恢复