前篇
过滤器Filter
- Filter也属于Servlet规范
- Filter开发步骤:新建类实现Filter接口,然后实现其中的三个方法:init、doFilter、destroy
- 配置Filter,可以用注解@WebFilter,也可以使用xml文件 filter、filter-mapping
- Filter在配置时,和servlet一样,也可以配置通配符,例如 @WebFilter("*.do")表示拦截所有以.do结尾的请求
- 过滤器链:
- 如果采取的是注解的方式进行配置,那么过滤器链的拦截顺序是按照全类名的先后顺序排序的
- 如果采取的是xml的方式进行配置,那么按照配置的先后顺序进行排序
- Filter执行的流程:请求过来之后,先进行过滤,然后进行放行,当返回数据时,又会进行过滤,然后再返回给浏览器。
- 编码举例:
@WebServlet("/demo01.do")
public class ServletDemo01 extends HttpServlet{
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("demo01...service..");
req.getRequestDispatcher("succ.html").forward(req,resp);
}
}
没有Filter的执行情况:
添加Filter:
/**
* @author crystal
* @create 2023-02-07 11:15
*/
@WebFilter("/demo01.do")
public class Demo01Filter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("filter ...");
//放行
filterChain.doFilter(servletRequest,servletResponse);
System.out.println("after filter...");
}
@Override
public void destroy() {
}
}
过滤器链编码举例:
@WebServlet("/demo02.do")
public class ServletDemo01 extends HttpServlet{
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("demo02...service..");
req.getRequestDispatcher("succ.html").forward(req,resp);
}
}
@WebFilter("*.do")
public class Filter01 implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("A");
filterChain.doFilter(servletRequest,servletResponse);
System.out.println("A2");
}
@Override
public void destroy() {
}
}
@WebFilter("*.do")
public class Filter02 implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("B");
filterChain.doFilter(servletRequest,servletResponse);
System.out.println("B2");
}
@Override
public void destroy() {
}
}
@WebFilter("*.do")
public class Filter03 implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("C");
filterChain.doFilter(servletRequest,servletResponse);
System.out.println("C2");
}
@Override
public void destroy() {
}
}
过滤器链的执行顺序(具体说明看第一段):
Filter的应用:
- 在请求到达DispatcherServlet、或者Controller层的时候,提前使用Filter设置编码,然后放行请求。
- 注解方式也可以替代成XML的方式。
@WebFilter(urlPatterns ={"*.do"} ,initParams = {@WebInitParam(name = "ecoding",value = "UTF-8")})
public class CharacterEncodingFilter implements Filter {
private String encoding = "UTF-8";
@Override
public void init(FilterConfig filterConfig) throws ServletException {
String encodingStr = filterConfig.getInitParameter("encoding");
if (StringUtil.isNotEmpty(encodingStr)){
encoding = encodingStr;
}
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
((HttpServletRequest)servletRequest).setCharacterEncoding("UTF-8");
filterChain.doFilter(servletRequest,servletResponse);
}
@Override
public void destroy() {
}
}
编程式事务管理应用
public class ConnUtil {
private static ThreadLocal<Connection> threadLocal = new ThreadLocal<>();
public static Connection createConn(){
try {
InputStream inputStream = ConnUtil.class.getClassLoader().getResourceAsStream("jdbc.properties");
Properties pros = new Properties();
pros.load(inputStream);
String driverClass = pros.getProperty("driverClass");
Class.forName(driverClass);
String url = pros.getProperty("url");
String user = pros.getProperty("user");
String password = pros.getProperty("password");
Connection connection = DriverManager.getConnection(url, user, password);
return connection;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
public static Connection getConn() throws SQLException {
Connection conn = threadLocal.get();
if (conn == null){
conn = createConn();
threadLocal.set(conn);
}
return threadLocal.get();
}
public static void close() throws SQLException {
Connection conn = threadLocal.get();
if (conn == null){
return;
}
if (!conn.isClosed()){
conn.close();
threadLocal.set(null);
}
}
}
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();
conn.close();
}
//回滚事务
public static void rollback() throws SQLException {
Connection conn = ConnUtil.getConn();
conn.rollback();
conn.close();
}
}
@WebFilter("*.do")
public class openSessionInViewFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
try {
// 开启事务
TransactionManager.beginTrans();
filterChain.doFilter(servletRequest,servletResponse);
// 提交事务
TransactionManager.commit();
}catch (Exception e){
e.printStackTrace();
try {
// 回滚事务
TransactionManager.rollback();
} catch (SQLException ex) {
ex.printStackTrace();
}
}
}
@Override
public void destroy() {
}
}
package com.crystal.myssm;
import com.crystal.exceptions.BaseDAOException;
import java.io.InputStream;
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;
import java.util.Properties;
/**
* @author crystal
* @create 2023-01-15 13:24
*/
public class BaseDAO<E> {
// 获取连接
public Connection getConn() throws SQLException {
return ConnUtil.getConn();
}
// 关闭连接
public void closeRes(Connection conn, PreparedStatement ps, ResultSet rs){
}
private Class clazz;
public BaseDAO(){
Type genericSuperclass = getClass().getGenericSuperclass();
Type[] actualTypeArguments = ((ParameterizedType) genericSuperclass).getActualTypeArguments();
Type argument = actualTypeArguments[0];
try {
clazz = Class.forName(argument.getTypeName());
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
// 获取所有的列表信息
public <E> List<E> getList(String sql,Object...args){
List list = new ArrayList<>();
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
conn = getConn();
ps = conn.prepareStatement(sql);
for (int i = 0; i < args.length; i++) {
ps.setObject(i + 1,args[i]);
}
rs = ps.executeQuery();
ResultSetMetaData metaData = rs.getMetaData();
int columnCount = metaData.getColumnCount();
while(rs.next()){
E e = (E) clazz.newInstance();
for (int i = 0; i < columnCount; i++) {
String columnLabel = metaData.getColumnLabel(i + 1);
Field field = e.getClass().getDeclaredField(columnLabel);
Object objectVal = rs.getObject(i + 1);
field.setAccessible(true);
field.set(e,objectVal);
}
list.add(e);
}
return list;
} catch (Exception e) {
e.printStackTrace();
throw new BaseDAOException("BaseaDAO出错了。。。");
}
}
// 获取单个的信息
public <E> E getOne(String sql,Object...args){
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
conn = getConn();
ps = conn.prepareStatement(sql);
for (int i = 0; i < args.length; i++) {
ps.setObject(i + 1,args[i]);
}
rs = ps.executeQuery();
ResultSetMetaData metaData = rs.getMetaData();
int columnCount = metaData.getColumnCount();
if (rs.next()){
E e = (E) clazz.newInstance();
for (int i = 0; i < columnCount; i++) {
String columnLabel = metaData.getColumnLabel(i + 1);
Object objectVal = rs.getObject(i + 1);
Field field = e.getClass().getDeclaredField(columnLabel);
field.setAccessible(true);
field.set(e,objectVal);
}
}
} catch (Exception e) {
e.printStackTrace();
throw new BaseDAOException("BaseaDAO出错了。。。");
}
return null;
}
// 修改单个信息
public int updateOne(String sql,Object...args){
Connection conn = null;
PreparedStatement ps = null;
try {
conn = getConn();
ps = conn.prepareStatement(sql);
for (int i = 0; i < args.length; i++) {
ps.setObject(i + 1,args[i]);
}
int val = ps.executeUpdate();
return val;
}catch (Exception e){
e.printStackTrace();
throw new BaseDAOException("BaseaDAO出错了。。。");
}
}
// 查询特殊值
public <E> E getValue(String sql,Object...args){
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
conn = getConn();
ps = conn.prepareStatement(sql);
for (int i = 0; i < args.length; i++) {
ps.setObject(i + 1,args[i]);
}
rs = ps.executeQuery();
if (rs.next()){
Object objectVal = rs.getObject(1);
return (E) objectVal;
}
}catch (Exception e){
e.printStackTrace();
throw new BaseDAOException("BaseaDAO出错了。。。");
}
return null;
}
}
package com.crystal.myssm;
import com.crystal.exceptions.BaseDAOException;
import com.crystal.exceptions.DispatcherServletException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.HashMap;
import java.util.Map;
/**
* @author crystal
* @create 2023-02-05 15:16
*/
@WebServlet("*.do")
public class DispatcherServlet extends ViewBaseServlet {
Map<String,Object> beanMap = new HashMap<>();
public DispatcherServlet(){
}
public void init() throws ServletException {
super.init();
try {
// 读取配置文件,将实例装进map集合
InputStream inputStream = getClass().getClassLoader().getResourceAsStream("applicationContext.xml");
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
Document document = documentBuilder.parse(inputStream);
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 id = beanElement.getAttribute("id");
String className = beanElement.getAttribute("class");
Class<?> clazz = Class.forName(className);
Object classObj = clazz.newInstance();
beanMap.put(id,classObj);
}
}
} catch (Exception e) {
e.printStackTrace();
throw new DispatcherServletException("DispatcherServlet出错了。。。");
}
}
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setCharacterEncoding("UTF-8");
// 获取请求的url:http://localhost:8080/pro/hello.do
// 第一步:getServletPath() 获取/hello.do
String servletPath = request.getServletPath();
// 第二步:从/hello.do获取hello.do
servletPath = servletPath.substring(1);
// 获取.do的索引
int lastDotIndexOf = servletPath.lastIndexOf(".do");
servletPath = servletPath.substring(0,lastDotIndexOf);
// 第三步:将获取到的hello ——> HelloController
Object beanObj = beanMap.get(servletPath);
// 获取前端的参数operate
String operate = request.getParameter("operate");
if (operate == null){
operate = "index";
}
// 根据反射调用方法
try {
// 获取方法的参数列表
Method[] methods = beanObj.getClass().getDeclaredMethods();
for (int i = 0; i < methods.length; i++) {
Method method = methods[i];
if (operate.equals(method.getName())){
Parameter[] parameters = method.getParameters();
Object[] parameterVals = new Object[parameters.length];
for (int j = 0; j < parameters.length; j++) {
Parameter parameter = parameters[j];
String parameterName = parameter.getName();
if ("request".equals(parameterName)){
parameterVals[j] = "request";
}else if ("response".equals(parameterName)){
parameterVals[j] = "response";
}else if ("session".equals(parameterName)){
parameterVals[j] = request.getSession();
}else{
String parameterval = request.getParameter(parameterName);
parameterVals[j] = parameterval;
Class<?> parameterType = parameter.getType();
Object parameterObj = parameterVals[j];
if (parameterObj != null){
if ("java.lang.Integer".equals(parameterType)){
parameterObj = Integer.parseInt(parameterval);
}
parameterVals[j] = parameterObj;
}
}
}
if (method != null){
// 调用controller中对应的方法
method.setAccessible(true);
Object ObjStr = method.invoke(beanObj,parameterVals);
// 视图处理
String returnStr = (String) ObjStr;
if (returnStr.startsWith("redirect:")){
String redirectVal = returnStr.substring("redirect:".length());
response.sendRedirect(redirectVal);
}else{
super.processTemplate(returnStr,request,response);
}
}else{
throw new RuntimeException("operate的值非法!");
}
}
}
} catch (Exception e) {
e.printStackTrace();
throw new DispatcherServletException("DispatcherServlet出错了。。。");
}
}
}
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)
else
createMap(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();
}
监听器
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域中的序列化和反序列化
ServletContextListener的应用 - ContextLoaderListener
@WebListener
public class ContextLoaderListener implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent servletContextEvent) {
ClassPathXmlApplicationContext beanFactory = new ClassPathXmlApplicationContext();
ServletContext application = servletContextEvent.getServletContext();
application.setAttribute("beanFactory",beanFactory);
}
@Override
public void contextDestroyed(ServletContextEvent servletContextEvent) {
}
}
package com.crystal.myssm;
import com.crystal.exceptions.BaseDAOException;
import com.crystal.exceptions.DispatcherServletException;
import com.crystal.ioc.BeanFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.HashMap;
import java.util.Map;
/**
* @author crystal
* @create 2023-02-05 15:16
*/
@WebServlet("*.do")
public class DispatcherServlet extends ViewBaseServlet {
private BeanFactory beanFactory;
public DispatcherServlet(){
}
public void init() throws ServletException {
super.init();
ServletContext servletContext = getServletContext();
Object beanFactoryObj = servletContext.getAttribute("beanFactory");
if (beanFactoryObj != null){
beanFactory = (BeanFactory) beanFactoryObj;
}
}
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setCharacterEncoding("UTF-8");
// 获取请求的url:http://localhost:8080/pro/hello.do
// 第一步:getServletPath() 获取/hello.do
String servletPath = request.getServletPath();
// 第二步:从/hello.do获取hello.do
servletPath = servletPath.substring(1);
// 获取.do的索引
int lastDotIndexOf = servletPath.lastIndexOf(".do");
servletPath = servletPath.substring(0,lastDotIndexOf);
// 第三步:将获取到的hello ——> HelloController
Object beanObj = beanFactory.getObj(servletPath);
// 获取前端的参数operate
String operate = request.getParameter("operate");
if (operate == null){
operate = "index";
}
// 根据反射调用方法
try {
// 获取方法的参数列表
Method[] methods = beanObj.getClass().getDeclaredMethods();
for (int i = 0; i < methods.length; i++) {
Method method = methods[i];
if (operate.equals(method.getName())){
Parameter[] parameters = method.getParameters();
Object[] parameterVals = new Object[parameters.length];
for (int j = 0; j < parameters.length; j++) {
Parameter parameter = parameters[j];
String parameterName = parameter.getName();
if ("request".equals(parameterName)){
parameterVals[j] = "request";
}else if ("response".equals(parameterName)){
parameterVals[j] = "response";
}else if ("session".equals(parameterName)){
parameterVals[j] = request.getSession();
}else{
String parameterval = request.getParameter(parameterName);
parameterVals[j] = parameterval;
Class<?> parameterType = parameter.getType();
Object parameterObj = parameterVals[j];
if (parameterObj != null){
if ("java.lang.Integer".equals(parameterType)){
parameterObj = Integer.parseInt(parameterval);
}
parameterVals[j] = parameterObj;
}
}
}
if (method != null){
// 调用controller中对应的方法
method.setAccessible(true);
Object ObjStr = method.invoke(beanObj,parameterVals);
// 视图处理
String returnStr = (String) ObjStr;
if (returnStr.startsWith("redirect:")){
String redirectVal = returnStr.substring("redirect:".length());
response.sendRedirect(redirectVal);
}else{
super.processTemplate(returnStr,request,response);
}
}else{
throw new RuntimeException("operate的值非法!");
}
}
}
} catch (Exception e) {
e.printStackTrace();
throw new DispatcherServletException("DispatcherServlet出错了。。。");
}
}
}
ServletContext应用-待更新
后续更新...