1. 监听器接口
监听器接口用于监控作用域对象生命周期变化时刻以及作用域对象共享数据变化时刻 。
ServletContextListener接口:检测全局作用域对象初始化时刻以及被销毁时刻;
(1)重写监听事件处理方法
public class OneListener implements ServletContextListener { @Override public void contextInitialized(ServletContextEvent sce) { //全局作用域对象被创建时调用 System.out.println("全局作用域对象被创建了"); } @Override public void contextDestroyed(ServletContextEvent sce) { //全局作用域对象被销毁时调用 System.out.println("全局作用域对象被销毁了"); } }
(2)在web.xml中将监听器接口实现类注册到tomcat中
<listener> <listener-class>com.lewang.listener.OneListener</listener-class> </listener>
在监听事件处理方法中:
public void contextInitialized():在全局作用域对象被http服务器初始化时被调用
public void contextDestory():在全局作用域对象被http服务器销毁时被调用
ServletContextAttributeListener接口:检查全局作用域对象共享数据变化时刻
(1)在OneServlet中获取全局作用域对象,并改变全局作用域对象;
public class OneServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { ServletContext application = req.getServletContext(); //获取全局作用域对象 application.setAttribute("key1",100); //添加全局作用域对象 application.setAttribute("key1",200); //更新全局作用域对象 application.removeAttribute("key1"); //删除全局作用域对象 } }
(2)在监听事件处理方法中监听对象的变化
public class OneListener implements ServletContextAttributeListener { @Override public void attributeAdded(ServletContextAttributeEvent scae) { System.out.println("全局作用域对象被添加了"); } @Override public void attributeRemoved(ServletContextAttributeEvent scae) { System.out.println("全局作用域对象被删除了"); } @Override public void attributeReplaced(ServletContextAttributeEvent scae) { System.out.println("全局作用域对象被更新了"); } }
(3)注册web.xml到tomcat后,对OneServlet发送请求后可以查看全局作用域对象数据的变化时刻。
监听器应用
在Servlet中对数据库进行处理时,可能需要频繁连接数据库,创建数据库连接对象,在创建数据库连接对象时比较耗时,这样我们可以预先创建好一定量的数据库连接对象作用全局作用域对象放在监听器中,等到我们需要连接数据库进行数据处理时可以直接获取全局作用域对象中的数据库连接对象,可以大大的减小时间消耗。
在监听器中初始化数据库连接对象
public void contextInitialized(ServletContextEvent sce) { JdbcUtil util = new JdbcUtil(); Map map = new HashMap(); for (int i=1; i<20; i++){ try { Connection con = util.getConnection(); System.out.println("创建connection" + con); map.put(con,true); } catch (SQLException e) { e.printStackTrace(); } } //为了在http服务运行期间都可以使用con,可以把con放在全局作用域对象中 ServletContext appliction = sce.getServletContext(); appliction.setAttribute("key1",map); }
在数据库工具类中重写getConnection和createStatement,使用已经创建的全局作用域对象中的数据库连接对象
public Connection getConnection(HttpServletRequest request){ ServletContext application = request.getServletContext(); Map map = (Map)application.getAttribute("key1"); Iterator it = map.keySet().iterator(); while (it.hasNext()){ connection = (Connection) it.next(); boolean flag = (boolean)map.get(connection); if(flag == true){ map.put(connection,false); break; } } return connection; } public PreparedStatement createStatement(String sql, HttpServletRequest request){ try { ps = getConnection(request).prepareStatement(sql); } catch (SQLException e) { e.printStackTrace(); } return ps; }
2. 过滤器接口
过滤器接口用于拦截http服务器,帮助http服务器检查当前请求合法性,也可以对当前请求进行增强操作。
检查请求合法性
(1)创建Filter接口实现类,重写类中doFilter方法
public class OneFilter implements Filter { @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { //1. 通过拦截请求对象获取请求参数中age的值 String age = servletRequest.getParameter("age"); //2. 拦截请求 if(Integer.valueOf(age) > 18){ filterChain.doFilter(servletRequest,servletResponse); }else { servletResponse.setContentType("text/html;charset=utf-8"); PrintWriter pw = servletResponse.getWriter(); pw.print("<font style='color:red;font-size:40px'>禁止访问</font>"); } } }
(2)web.xml将过滤器接口实现类注册到tomcat中
<filter> <filter-name>onefilter</filter-name> <filter-class>com.lewang.filter.OneFilter</filter-class> </filter> <filter-mapping> <filter-name>onefilter</filter-name> <url-pattern>/ff.jpeg</url-pattern> <!--当访问/ff.jpeg是进行拦截--> </filter-mapping>
(3)当发送请求访问时会对非法请求拦截
对当前请求进行增强处理
(1)默认情况下我们发送post请求,从请求体中获取的中文时乱码,这时我们需要重新设置编码格式,但是如果有多个servlet的话,那么我们就需要每一个servlet中都需要设置编码格式,显然这样是复杂的,所以我们可以使用过滤器来统一设置一次编码格式。
在Filter过滤器接口实现类中设置编码格式
public class OneFilter implements Filter { @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { //先对请求对象拦截,然后重新设置编码格式 servletRequest.setCharacterEncoding("utf-8"); //然后重新交给tomcat filterChain.doFilter(servletRequest,servletResponse); } }
在Servlet中就可以不用在设置编码格式了,即使有多个Servlet也都不用在设置编码格式
public class OneServlet extends HttpServlet { @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //在不设置拦截器时接从请求体中获取参数是乱码,如果是多个servlet则需要设置多个编码格式 //所以可以在拦截器中对所有请求对象设置编码格式 String username = req.getParameter("userName"); System.out.println("从OneServlet请求体中获取参数:" + username); } }
public class TwoServlet extends HttpServlet { @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String username = req.getParameter("userName"); System.out.println("从TwoServlet请求体中获取参数:" + username); } }
在web.xml中注册过滤器和Servlet
.
.
. <filter-mapping> <filter-name>onefilter</filter-name> <url-pattern>/*</url-pattern> <!--对所有请求资源进行拦截--> </filter-mapping>
Filter拦截地址规则
(1)要求tomcat在调用某一个文件之前进行拦截;
<url-pattern>/img/ff.jpeg</url-pattern>
(2)要求tomcat在调用某一个文件夹下所有资源之前进行拦截;
<url-pattern>/img/*</url-pattern>
(3)要求tomcat在调用任意文件夹下某中类型文件之前进行拦截;
<url-pattern>/*.jpeg</url-pattern>
(4)要求tomcat在调用网站下任意文件都进行拦截
<url-pattern>/*</url-pattern>
3. JSP规范
JSP规范定义了如果开发JSP文件代替响应对象将处理结果写入到响应体的开发流程;在传统方式中,使用Servlet的响应对象获取输出流,print()也可以把数据写入到响应体中,但是这种方式一般适用于少量数据写入响应体中,大量数据写入通常使用JSP。
JSP书写规范
在执行标记<% %>中写Java表达式
<% int num1 = 100; int num2 = 200; Student s = new Student(); s.setAge(10); s.setNo(20); List list = new ArrayList(); <!--同一用户/浏览器可以使用session共享数据--> session.setAttribute("name","james"); <!--同一网站中Servlet和JSP,都可以通过当前网站的全局作用域共享对象实现数据共享--> application.setAttribute("key1","hello,world"); %>
在输出标记<%= %>中获取值
<%=num1%> <%=num2%> <%=num1+num2%> <%=s.getNo()%> <%=s.getAge()%>
Http服务器调用JSP文件步骤
(1)Http服务器将JSP文件内容编辑为一个Servlet接口实现类(.java);
(2)Http服务器将Servlet接口实现类编译为class文件(.class);
(3)Http服务器负责创建这个class的实例对象,这个实例对象就是Servlet实例对象;
(4)Http服务器通过Servlet实例对象调用_jspService方法,将jsp文件内容写入响应体中;
4. EL表达式
EL表达式在JSP文件上使用,是JSP书写类型的简化,负责在JSP文件上从作用域对象读取指定的共享数据并输出到响应体中;
示例:分别使用传统方式和el表达式获取作用域对象中的值
public class OneServlet extends HttpServlet { protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { Student s1 = new Student(23,"james"); request.setAttribute("key1",s1); request.getRequestDispatcher("/index_1.jsp").forward(request,response); } }
在JSP文件中
<!--1. 传统方式-->
<% Student s1 = (Student)request.getAttribute("key1"); %> 学生编号:<%=s1.getSno()%> 学生姓名:<%=s1.getSname()%> <hr> <!--2. 使用el表达式--> 学生编号:${requestScope.key1.sno} 学生姓名:${requestScope.key1.sname}
可以看到EL表达式使用规则:
${作用域对象别名.共享数据名.属性名}
(1)EL表达式提供作用域对象别名
a. ${applicationScope.共享数据名}
b. ${sessionScope.共享数据名}
c. ${requestScope.共享数据名}
d. ${pageScope.共享数据名} pageCotext 当前页作用域对象,是JSP中特有的,Servlet中没有,所有只能在当前JSP文件中使用,不能共享给其他Servlet和JSP文件。
(2)EL表达式简化版
在实际写EL表达式时允许省略作用域对象别名
public class OneServlet extends HttpServlet { protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { HttpSession session = request.getSession(); session.setAttribute("key","james"); request.setAttribute("key","kobe"); request.getRequestDispatcher("/index_1.jsp").forward(request,response); } }
使用标准版el表达式获取作用域对象中的值:${sessionScope.key} <hr> 使用简化版el表达式获取作用域对象中的值:${key}
使用简化版EL表达式时可以不用写作用域对象别名,直接用共享数据名获取共享数据。
这样就存在一个问题了,如果共享数据名都是key,那么到底是从session中获取还是从request中获取呢?
实际是从request中获取,EL表达式简化版获取共享数据有定位顺序,先到pageContext定位共享数据,如果存在则读取,否则到request中定位共享数据,同样的如果存在则读取数据,否则到session中定位数据,最后是application中。
所以上面使用标准版获取的共享数据是james,使用简化版获取的共享数据是kobe。
使用EL表达式没有提供遍历集合方法,因此无法从作用域对象中读取集合内容的输出。
5. JSON格式转换
第一种方式:使用反射获取实体类中的属性和值,添加到字符串中,在Servlet中通过请求作用域对象共享给JSP。
public class ReflectUtilTest { public static String JsonObjMethod(Object obj){ Class objclass = obj.getClass(); Field[] fields = objclass.getDeclaredFields(); StringBuffer sb = new StringBuffer(); sb.append("{"); try{ for(Field field : fields){ field.setAccessible(true); String name = field.getName(); Object value = field.get(obj); sb.append("\""); sb.append(name); sb.append("\":"); sb.append("\""); sb.append(value); sb.append("\""); sb.append(","); } }catch (Exception e){} if(sb.toString().endsWith(",")){ sb.deleteCharAt(sb.length()-1); } sb.append("}"); return sb.toString(); } }
public class OneServlet extends HttpServlet { protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { Student s1 = new Student(23,"james"); String str = ReflectUtilTest.JsonObjMethod(s1); request.setAttribute("key",str); request.getRequestDispatcher("/index_1.jsp").forward(request,response); } }
第二种方式:直接使用JSON工具包类(json-lib-2.4-jdk15.jar)
a. 使用工具类转换一个对象到JSON格式
public class OneServlet extends HttpServlet { protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { Dept dept = new Dept(10,"人事部","西安"); //使用json.jar工具类把dept对象转换为json格式字符串 JSONObject object = JSONObject.fromObject(dept); request.setAttribute("key",object.toString()); request.getRequestDispatcher("/index_1.jsp").forward(request,response); } }
b. 使用工具类转化一个集合类对象到一个JSON数组,在jsp中对JSON数组处理。
public class TwoServlet extends HttpServlet { protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { Dept d1 = new Dept(10,"人事部","高新区"); Dept d2 = new Dept(20,"研发部","雁塔区"); Dept d3 = new Dept(30,"销售部","高陵区"); List list = new ArrayList(); list.add(d1); list.add(d2); list.add(d3); //通过json.jar包把集合转换为Json数组 JSONArray jsonArray = JSONArray.fromObject(list); request.setAttribute("key",jsonArray); request.getRequestDispatcher("index_2.jsp").forward(request,response); } }