文章目录
- 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
@Override
public 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);
}
@Override
public void contextDestroyed(ServletContextEvent servletContextEvent) {
System.out.println("应用程序关闭,可以做一些资源的释放");
}
}
/**
* localhost:8080/demo1/picture/fetch?name=1.jpg
*/
@WebServlet("/picture/fetch")
public class PictureAccessServlet extends HttpServlet {
@Override
protected 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 {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
ServletContext servletContext = filterConfig.getServletContext();
}
@Override
public 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
// 后半部分
// 但是一般业务代码都写在前半部分
}
@Override
public 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 {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
process(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
process(req, resp);
}
@SneakyThrows
private void process(HttpServletRequest request, HttpServletResponse response) {
DispatchUtil.dispatch(request,response,this);
}
@SneakyThrows
private 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 {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
process(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
process(req, resp);
}
@SneakyThrows
private void process(HttpServletRequest request, HttpServletResponse response) {
DispatchUtil.dispatch(request, response, this);
}
@SneakyThrows
private 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");
}
}
@SneakyThrows
private void logout(HttpServletRequest request, HttpServletResponse response){
HttpSession session = request.getSession();
session.invalidate();
response.getWriter().println("注销用户");
}
@SneakyThrows
private 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 {
@Override
public 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);
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
}
}
filter
目录下
@WebFilter("/*")
public class CharacterEncodingFilter implements Filter {
List<String> whiteList = null;
@SneakyThrows
@Override
public 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");
}
@Override
public 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");
// }
}
@Override
public 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 - contextPath
String uriSuffix = null;
// eg: /demo3/user/name
String requestURI = request.getRequestURI();
// eg: /demo3
String 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处理前后增加通用的处理