文章目录
- Web组件
- Listener监听器
- ServletContextListener
- 执行过程
- Filter过滤器
- Filter与Servlet的执行
- 案例(登录案例)
- 小结
- Web组件
Web组件
- JavaEE的Web组件(三大Web组件):
Servlet
→ 处理请求对应的业务Listener
→ 监听器Filter
→ 过滤器
Listener监听器
- 监听器在监听到主体做了XX事情,就会触发对应的事件
- 监听的东西与命名有关系
- 要加上注解
@WebListener
ServletContextListener
监听的主体就是ServletContext,当发现ServletContext做了事情,Listener(监听器)就会执行该事件特定的方法。
- ServletContext如果初始化,则会执行监听器的初始化方法
contextInitialized
- ServletContext应用程序启动的时候初始化,就意味着应用程序启动
- ServletContext如果销毁,则会执行监听器的销毁方法
contextDestroy
- ServletContext应用程序关闭的时候销毁,意味着应用程序关闭
- 应用程序启动的时候会执行
ServletContextListener
的contextInitialized
方法;应用程序关闭的时候会执行contextDestroy
执行过程
当应用程序启动的过程中,逐步加载Web组件
- 首先会加载
ServletContext
和Listener
组件- ServletContext伴随着应用程序初始化,它开始初始化,然后ServletContextListener监听到ServletContext初始化,会执行Listener的Initialized方法
- 然后初始化
loadOnStartup
为正数的Servlet
eg:
@WebListener
public class PropertyInitServletContextListener implements ServletContextListener {@SneakyThrows@Overridepublic void contextInitialized(ServletContextEvent servletContextEvent) {ServletContext servletContext = servletContextEvent.getServletContext();InputStream inputStream = PropertyInitServletContextListener.class.getClassLoader().getResourceAsStream("parameter.properties");Properties properties = new Properties();properties.load(inputStream);String picPath = properties.getProperty("pic.path");servletContext.setAttribute("picPath", picPath);}@Overridepublic void contextDestroyed(ServletContextEvent servletContextEvent) {System.out.println("应用程序关闭,可以做一些资源的释放");}
}
/*** localhost:8080/demo1/picture/fetch?name=1.jpg*/
@WebServlet("/picture/fetch")
public class PictureAccessServlet extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {// InputStream inputStream = PictureAccessServlet.class.getClassLoader()// .getResourceAsStream("parameter.properties");// Properties properties = new Properties();// properties.load(inputStream);// String path = properties.getProperty("pic.path");String path = (String) getServletContext().getAttribute("picPath");File file = new File(path,request.getParameter("name"));FileInputStream fileInputStream = new FileInputStream(file);ServletOutputStream outputStream = response.getOutputStream();int length = 0;byte[] bytes = new byte[1024];while((length = fileInputStream.read(bytes)) != -1) {outputStream.write(bytes,0,length);}fileInputStream.close();outputStream.close();}
}
Filter过滤器
- Filter是一个执行过滤任务的一个对象
- 它既可以作用于
Request
对象,也可以作用于Response
对象,或者两者均作用
- 它既可以作用于
- 就是Servlet中获取请求之前,Servlet响应之后
Filter与Servlet的执行
- URL-Pattern和Servlet之间存在着映射关系,URL-Pattern和Filter之间也存在着映射关系
- 1个URL-Pattern只能对应一个Servlet,但是可以对应多个Filter
- Servlet和URL-Pattern之间是一对多的关系,但是URL-Pattern和Servlet之间是一对一
- 其实,一个URL-Pattern对应的请求
- 对应1个Servlet
- 对应多个Filter
eg:
@WebFilter("/user/*")
public class CharacterEncodingFilter implements Filter {@Overridepublic void init(FilterConfig filterConfig) throws ServletException {ServletContext servletContext = filterConfig.getServletContext();}@Overridepublic void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)throws IOException, ServletException {// 做过滤,里面写的就是通用的业务// 前半部分// 这部分是解决中文乱码问题HttpServletResponse response = (HttpServletResponse) servletResponse;HttpServletRequest request = (HttpServletRequest) servletRequest;request.setCharacterEncoding("utf-8");response.setContentType("text/html;charset=utf-8");filterChain.doFilter(servletRequest, servletResponse); // 执行下一个过滤器或者Servlet// 后半部分// 但是一般业务代码都写在前半部分}@Overridepublic void destroy() {}
}
案例(登录案例)
- 需求
/user/login
/user/logout
/user/info
/order/list
- 增加web组件中的filter功能
- 增加web组件中的listener功能
- 增加白名单功能
bean
目录下
@Data
public class Order {private Integer id;private String name;private Double price;private Integer userId;
}
@Data
public class User {private Integer id;private String username;private String password;private Integer age;private Date birthday;private Date createdate;private String mobile;}
mapper
目录下
public interface OrderMapper {List<Order> selectByUserId(Integer id);
}
public interface UserMapper {List<User> selectByUserNameAndPassword(@Param("username") String username, @Param("password") String password);User selectByPrimaryKey(Integer id);
}
servlet
目录下
@WebServlet("/order/*")
public class OrderServlet extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp)throws ServletException, IOException {process(req, resp);}@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp)throws ServletException, IOException {process(req, resp);}@SneakyThrowsprivate void process(HttpServletRequest request, HttpServletResponse response) {DispatchUtil.dispatch(request,response,this);}@SneakyThrowsprivate void list(HttpServletRequest request, HttpServletResponse response){// 先判断是否是登录状态// 如果没有登录,则跳转到登录页面// 这里filter帮我们完成了// 如果已经登录,则查询orderlist信息OrderMapper orderMapper = MybatisUtil.getSqlSession().getMapper(OrderMapper.class);HttpSession session = request.getSession();User user = (User) session.getAttribute("user");List<Order> orders = orderMapper.selectByUserId(user.getId());response.getWriter().println(orders);}
}
@WebServlet("/user/*")
public class UserServlet extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp)throws ServletException, IOException {process(req, resp);}@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp)throws ServletException, IOException {process(req, resp);}@SneakyThrowsprivate void process(HttpServletRequest request, HttpServletResponse response) {DispatchUtil.dispatch(request, response, this);}@SneakyThrowsprivate void login(HttpServletRequest request, HttpServletResponse response){// 获取username和password,查询user记录String username = request.getParameter("username");String password = request.getParameter("password");UserMapper userMapper = MybatisUtil.getSqlSession().getMapper(UserMapper.class);List<User> users = userMapper.selectByUserNameAndPassword(username, password);// 有可能用户名和密码相同,则取第一条数据if (users != null && users.size() > 0) {User user = users.get(0);HttpSession session = request.getSession();session.setAttribute("user",user);response.getWriter().println("登录成功");} else {response.getWriter().println("用户名或密码错误,即将跳转到登录页面...");response.setHeader("refresh","2;url=/demo3/login.html");}}@SneakyThrowsprivate void logout(HttpServletRequest request, HttpServletResponse response){HttpSession session = request.getSession();session.invalidate();response.getWriter().println("注销用户");}@SneakyThrowsprivate void info(HttpServletRequest request, HttpServletResponse response){// 先判断是否是登录状态// 如果没有登录,则跳转到登录页面// 这里filter帮我们做了// 如果已经登录,可以从session中获取信息 -> 响应信息HttpSession session = request.getSession();User user = (User) session.getAttribute("user");response.getWriter().println(user);}
}
listener
目录下
@WebListener
public class PropertyServletContextListener implements ServletContextListener {@Overridepublic void contextInitialized(ServletContextEvent servletContextEvent) {ServletContext servletContext = servletContextEvent.getServletContext();Properties properties = new Properties();InputStream inputStream = PropertyServletContextListener.class.getClassLoader().getResourceAsStream("application.properties");try {properties.load(inputStream);} catch (IOException e) {e.printStackTrace();}String whiteList = properties.getProperty("whiteList");String[] whiteListStr = whiteList.split(",");List<String> list = Arrays.asList(whiteListStr);servletContext.setAttribute("whiteList", list);}@Overridepublic void contextDestroyed(ServletContextEvent sce) {}
}
filter
目录下
@WebFilter("/*")
public class CharacterEncodingFilter implements Filter {List<String> whiteList = null;@SneakyThrows@Overridepublic void init(FilterConfig filterConfig) throws ServletException {// 方法1:
// Properties properties = new Properties();
// InputStream inputStream = CharacterEncodingFilter.class.getClassLoader()
// .getResourceAsStream("application.properties");
// properties.load(inputStream);
// String whiteListStr = properties.getProperty("whiteList");
// String[] whiteArray = whiteListStr.split(",");
// whiteList = Arrays.asList(whiteArray);// 方法2:// 可以先把配置文件在Listener的时候放入whiteList = (List<String>) filterConfig.getServletContext().getAttribute("whiteList");}@Overridepublic void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)throws IOException, ServletException {// List<String> list = Arrays.asList("/user/login", "/user/logout", "/login.html");// 强转HttpServletRequest request = (HttpServletRequest) servletRequest;HttpServletResponse response = (HttpServletResponse) servletResponse;String uriSuffix = UriUtil.getUriSuffix(request);if (whiteList.contains(uriSuffix)) {if (!uriSuffix.endsWith("html")) {// 1. 解决字符集request.setCharacterEncoding("utf-8");// 响应的字符集问题response.setContentType("text/html;charset=utf-8");}filterChain.doFilter(request, response);}// 1. 解决字符集request.setCharacterEncoding("utf-8");// 响应的字符集问题response.setContentType("text/html;charset=utf-8");// 2. 解决登录状态的判断HttpSession session = request.getSession();Object user = session.getAttribute("user");// 2.1 如果已经登录(或者登录/注销请求)就放行if (user != null) {filterChain.doFilter(request, response);} else {// 2.2 如果没有登录就提示,跳转到登录页面response.getWriter().println("没有登录,请先登录,即将跳转到登录页面...");response.setHeader("refresh", "2;url=/demo3/login.html");}// String requestURI = request.getRequestURI();// if (requestURI.endsWith("html")) {
// filterChain.doFilter(request, response);
// }// 2.1 如果已经登录(或者登录/注销请求)就放行
// if (user != null || requestURI.endsWith("login")
// || requestURI.endsWith("logout")){
// filterChain.doFilter(request, response);
// } else {
// // 2.2 如果没有登录就提示,跳转到登录页面
// response.getWriter().println("没有登录,请先登录,即将跳转到登录页面...");
// response.setHeader("refresh","2;url=/demo3/login.html");
// }}@Overridepublic void destroy() {}
}
util
目录下
public class DispatchUtil {public static void dispatch(String operation, HttpServletRequest request, HttpServletResponse response, HttpServlet instance)throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {Method method = instance.getClass().getDeclaredMethod(operation, HttpServletRequest.class, HttpServletResponse.class);method.setAccessible(true);method.invoke(instance, new Object[]{request, response});}public static void dispatch(HttpServletRequest request, HttpServletResponse response, HttpServlet userServlet)throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {String requestURI = request.getRequestURI();String operation = requestURI.substring(requestURI.lastIndexOf("/") + 1);dispatch(operation, request, response, userServlet);}
}
public class MybatisUtil {private static SqlSession sqlSession;static{try {sqlSession = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("mybatis.xml")).openSession(true);} catch (IOException e) {e.printStackTrace();}}public static SqlSession getSqlSession() {return sqlSession;}
}
public class UriUtil {// Suffix的意思是后缀public static String getUriSuffix(HttpServletRequest request) {// uri - contextPathString uriSuffix = null;// eg: /demo3/user/nameString requestURI = request.getRequestURI();// eg: /demo3String contextPath = request.getContextPath();if (contextPath == null || contextPath.length() == 0) {// 这是一个root应用uriSuffix = requestURI;} else {uriSuffix = requestURI.replaceAll(contextPath, "");// 或者:uriSuffix = requestURI.substring();}return uriSuffix;}
}
UserMapper
的xml
目录
<mapper namespace="com.coo1heisenberg.demo3.mapper.OrderMapper"><select id="selectByUserId" resultType="com.coo1heisenberg.demo3.bean.Order">select id, name, price, user_id as userId from test_product<where>user_id = #{user_id}</where></select>
</mapper>
<mapper namespace="com.coo1heisenberg.demo3.mapper.UserMapper"><select id="selectByUserNameAndPassword" resultType="com.coo1heisenberg.demo3.bean.User">select id, username, password, age, birthday, createDate, mobile from test_user<where>username = #{username} and password = #{password}</where></select><select id="selectByPrimaryKey" resultType="com.coo1heisenberg.demo3.bean.User">select id, username, password, age, birthday, createDate, mobile from test_user<where>id = #{id}</where></select>
</mapper>
小结
Web组件
- 核心是
Servlet
,处理核心业务 Listener
,用来做资源的初始化Filter
,在Servlet处理前后增加通用的处理