JavaEE基础知识

JSP的基本原理

JSP的本质是Servlet,当用户想指定Servlet发送请求时,Servlet利用输出流动态生成HTML页面,包括每一个静态HTML标签和所有HTML页面中出现的内容。

JSP的三个编译指令

  • page
    <%@ page 属性%>
  • include
    这是一个静态include指令,静态包含会将包含页面的额编译指令也包含进来,如果两个页面的编译指令冲突,那么页面就会出错.
  • taglib

JSP动作指令

  • jsp:forward
  • jsp:param
  • jsp:include
  • jsp:plugin
  • jsp:useBean
  • jsp:setProperty
  • jsp:getProperty

JSP的9个内置对象

  • application:
  • config: JSP页面通常无需配置,该对象更多地在Servlet中有效;
  • exception: 编译指令page的isErrorPage属性为true时,该对象才可以使用。常用的方法有getMessage()和printStackTrace()等;
  • out:
  • page: 通常没有太大用处。也就是Servlet中的this.
  • pageContext: 代表JSP页面上下文,使用该对象可以访问页面中的共享数据;常用方法:
    • getAttribute(String name): 取得page范围内的name属性;
    • getAttribute(String name, int scope): 取得指定范围内的额那么属性,其中scope可以是四个值:
      1. PageContext.PAGE_SCOPE
      2. PageContext.REQUEST_SCOPE
      3. PageContext.SESSION_SCOPE
      4. PageContext.APPLICATION_SCOPE。
  • request: 常用方法:
    • getParameter
    • getParameterValues
    • setAttribute
    • getAttribute
    • setCharacterEncoding;
  • session: 代表一次会话,常用方法getAttribute, setAttribute;
  • response: 通常很少使用该对象直接响应,而是使用out对象,除非需要生成非字符响应。response对象常用语重定向,常用方法getOutputStream, sendRedirect;

forward和redirect

转发(forward) 重定向(redirect)
执行forward后依然是上一次请求 执行redirect后生成第二次请求
Forward的目标页面可以访问原请求参数,因为依然是同一次请求,所有原请求的请求参数、request范围的属性全部存在 Redirect的目标页面不能访问原请求的请求参数,因为是第二次请求,所有原请求的请求参数、request方位的属性全部丢失
地址栏里请求的URL不会改变 地址栏改为重定向的目标URL。相当于在浏览器地址栏里输入新的URL后按回车键
String name = request.getParameter("name");
Cookie c = new Cookie("username" , name);
c.setMaxAge(24 * 3600);
response.addCookie(c);
Cookie[] cookies = request.getCookies();
for (Cookie c : cookies)
{
    if(c.getName().equals("username"))
    {
        out.println(c.getValue());
    }
}
Cookie c = new Cookie("cnName" 
    , java.net.URLEncoder.encode("孙悟空" , "gbk"));
c.setMaxAge(24 * 3600);
response.addCookie(c);
Cookie[] cookies = request.getCookies();
for (Cookie cookie : cookies)
{
    if(cookie.getName().equals("cnName"))
    {
        out.println(java.net.URLDecoder
            .decode(cookie.getValue()));
    }
}

Servlet

Servlet和JSP的区别

  • Servlet中没有内置对象,原来JSP中的内置对象都必须由程序显示创建;
  • 对于静态的HTML标签,Servlet都必须使用页面输出流逐行输出;

两种配置方式:

  • 在Servlet类中使用@WebServlet标记;
  • 在web.xml文件中进行配置;

@WebServlet支持的常用属性

属性 是否必须 说明
asyncSupported 指定该Servlet是否支持异步操作模式。
displayName 指定该Servlet的显示名
initParams 用于为该Servlet配置参数
loadOnStartup 用于将该Servlet配置成load-on-startup的Servlet
name 指定该Servlet的名称
urlPatterns/value 这两个属性的作用完全相同

如果打算使用注解配置Servlet,注意两点:

  • 不要在web.xml文件的根元素(

如果打算使用web.xml文件来配置该Servlet,则需要配置如下两个部分:

  • 配置Servlet的名字:对应web.xml文件中的servlet/>元素;
  • 配置Servlet的URL:对应web.xml文件中的servlet-mapping/>元素。这一步是可选的。但如果没有为Servlet配置URL,则该Servlet不能响应用户请求;

<web-app xmlns="http://java.sun.com/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
    http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
    version="3.0">
    
    <servlet>
        
        <servlet-name>firstServletservlet-name>
        
        <servlet-class>lee.FirstServletservlet-class>
    servlet>
    
    <servlet-mapping>
        
        <servlet-name>firstServletservlet-name>
        
        <url-pattern>/aaurl-pattern>
    servlet-mapping>
    <servlet>
        
        <servlet-name>timerServletservlet-name>
        
        <servlet-class>lee.TimerServletservlet-class>
        
        <load-on-startup>1load-on-startup>
    servlet>
    <servlet>
        
        <servlet-name>testServletservlet-name>
        
        <servlet-class>lee.TestServletservlet-class>
        
        <init-param>
            <param-name>driverparam-name>
            <param-value>com.mysql.jdbc.Driverparam-value>
        init-param>
        
        <init-param>
            <param-name>urlparam-name>
            <param-value>jdbc:mysql://localhost:3306/javaeeparam-value>
        init-param>
        
        <init-param>
            <param-name>userparam-name>
            <param-value>rootparam-value>
        init-param>
        
        <init-param>
            <param-name>passparam-name>
            <param-value>32147param-value>
        init-param>
    servlet>
    <servlet-mapping>
        
        <servlet-name>testServletservlet-name>
        
        <url-pattern>/testServleturl-pattern>
    servlet-mapping>
web-app>

JSP/Servlet的声明周期

创建Servlet实例有两个时机:

  • 客户端第一次请求某个Servlet时,系统创建该Servlet的实例:大部分的Servlet都是这种Servlet。
  • Web应用启动时立即创建Servlet实例,即load-on-startup Servlet;

每个Servlet的运行都遵循如下声明周期:

  • 创建Servlet实例;
  • Web容器调用Servlet的init方法,对Servlet进行初始化;
  • Servlet初始化后,将一直存在于容器中,用于响应客户端请求。Get请求调用doGet方法响应;Post请求调用doPost方法响应请求。或者统一使用service()方法处理来响应用于请求。
  • Web容器决定销毁Servlet时,先调用Servlet的destroy方法,通常在关闭Web应用之时销毁Servlet。

Filter

Filter主要用于对用户请求进行预处理,也可以对HttpServletResponse进行后处理,是个典型的处理链。使用流程:Filter对用于请求进行预处理,接着讲请求交给Servlet进行处理并生成响应,最后Filter再对服务器响应进行后处理。

Filter的几个用处:

  • 在HttpServletRequest到达Servlet之前,拦截用户的HttpServletRequest;
  • 根据需要检查HttpServletRequest,也可以修改HttpServletRequest头和数据;
  • 在HttpServletResponse到达客户端之前,拦截HttpServletResponse。
  • 根据需要检查HttpServletResponse,也可以修改HttpServletResponse头和数据;

Filter种类

  • 用户授权的Filter:Filter负责检查用户请求,根据请求过滤用户非法请求;
  • 日志Filter: 详细记录某些特殊的用户请求;
  • 负责解码的Filter:包括对非标准编码的请求解码;
  • 能改变XML内容的XSLT Filter等;
  • Filter可负责拦截多个请求或响应: 一个请求或响应也可被多个Filter拦截;

创建Filter的两个步骤:

  • 实现javax.servlet.Filter接口:三个方法: init, destroy, deFilter
  • web.xml文件中配置Filter;
@WebFilter(filterName="log"
    ,urlPatterns={"/*"})
public class LogFilter implements Filter 
{
    //FilterConfig可用于访问Filter的配置信息
    private FilterConfig config;
    //实现初始化方法
    public void init(FilterConfig config)
    {
        this.config = config; 
    }
    //实现销毁方法
    public void destroy()
    {
        this.config = null; 
    }
    //执行过滤的核心方法
    public void doFilter(ServletRequest request,
        ServletResponse response, FilterChain chain)
        throws IOException,ServletException
    {
        //---------下面代码用于对用户请求执行预处理---------
        //获取ServletContext对象,用于记录日志
        ServletContext context = this.config.getServletContext(); 
        long before = System.currentTimeMillis();
        System.out.println("开始过滤...");
        //将请求转换成HttpServletRequest请求
        HttpServletRequest hrequest = (HttpServletRequest)request;
        //输出提示信息
        System.out.println("Filter已经截获到用户的请求的地址: " + 
            hrequest.getServletPath());
        //Filter只是链式处理,请求依然放行到目的地址
        chain.doFilter(request, response);
        //---------下面代码用于对服务器响应执行后处理---------
        long after = System.currentTimeMillis();
        //输出提示信息
        System.out.println("过滤结束");
        //输出提示信息
        System.out.println("请求被定位到" + hrequest.getRequestURI() + 
            "   所花的时间为: " + (after - before)); 
    } 
}

一个较为实用的Filter

设置request编码的字符集,从而避免每个JSP、Servlet都需要设置;而且还会验证用户是否登录,如果用户没有登录,系统直接跳转到登录页面;

@WebFilter(filterName="authority"
    , urlPatterns={"/*"}
    , initParams={
        @WebInitParam(name="encoding", value="GBK"),
        @WebInitParam(name="loginPage", value="/login.jsp"),
        @WebInitParam(name="proLogin", value="/proLogin.jsp")})
public class AuthorityFilter implements Filter 
{
    //FilterConfig可用于访问Filter的配置信息
    private FilterConfig config;
    //实现初始化方法
    public void init(FilterConfig config)
    {
        this.config = config; 
    }
    //实现销毁方法
    public void destroy()
    {
        this.config = null; 
    }
    //执行过滤的核心方法
    public void doFilter(ServletRequest request,
        ServletResponse response, FilterChain chain)
        throws IOException,ServletException
    {
        //获取该Filter的配置参数
        String encoding = config.getInitParameter("encoding");
        String loginPage = config.getInitParameter("loginPage");
        String proLogin = config.getInitParameter("proLogin");
        //设置request编码用的字符集
        request.setCharacterEncoding(encoding);         //①
        HttpServletRequest requ = (HttpServletRequest)request;
        HttpSession session = requ.getSession(true);
        //获取客户请求的页面
        String requestPath = requ.getServletPath();
        //如果session范围的user为null,即表明没有登录
        //且用户请求的既不是登录页面,也不是处理登录的页面
        if( session.getAttribute("user") == null
            && !requestPath.endsWith(loginPage)
            && !requestPath.endsWith(proLogin))
        {
            //forward到登录页面
            request.setAttribute("tip" , "您还没有登录");
            request.getRequestDispatcher(loginPage)
                .forward(request, response);
        }
        //"放行"请求
        else
        {
            chain.doFilter(request, response);
        }
    } 
}

实用URL Rewrite实现网站伪静态

搜索引擎会优先考虑收录静态的HTML页面,大部分网站都是动态的。实现伪静态:可以通过Filter拦截所有发向.html请求,然后按某种规则将请求forward到实际的.jsp页面即可。
- 下载Jar包: http://www.tuckey.org/urlrewrite/
- 在web.xml文件中配置:

<filter>
        <filter-name>UrlRewriteFilterfilter-name>
        <filter-class>org.tuckey.web.filters.urlrewrite.UrlRewriteFilterfilter-class>
filter>
<filter-mapping>
    <filter-name>UrlRewriteFilterfilter-name>
    <url-pattern>/*url-pattern>
filter-mapping>
  • 在WEB-INF路径下增加urlrewrite.xml文件,该文件定义了伪静态映射规则,这份伪静态规则是基于正则表达式的。


<urlrewrite>
    <rule>
        
        <from>/userinf-(\w*).htmlfrom>
        
        <to type="forward">/userinf.jsp?username=$1to>
    rule>
urlrewrite>

Listener

常用的Web事件监听器接口:

  • ServletContextListener: 用于监听Web应用的启动和关闭;
@WebListener
public class GetConnListener implements ServletContextListener
{
    //应该启动时,该方法被调用。
    public void contextInitialized(ServletContextEvent sce)
    {

    }
    //应该关闭时,该方法被调用。
    public void contextDestroyed(ServletContextEvent sce)
    {

    }
}
  • ServletContextAttributeListener: 用于监听ServletContext范围(application)内属性的改变;
@WebListener
public class MyServletContextAttributeListener
    implements ServletContextAttributeListener
{
    //当程序向application范围添加属性时触发该方法
    public void attributeAdded(ServletContextAttributeEvent event) 
    {
        ServletContext application = event.getServletContext();
        //获取添加的属性名和属性值
        String name = event.getName();
        Object value = event.getValue();
        System.out.println(application + "范围内添加了名为"
            + name + ",值为" + value + "的属性!");
    }
    //当程序从application范围删除属性时触发该方法
    public void attributeRemoved(ServletContextAttributeEvent event)
    {
        ServletContext application = event.getServletContext();
        //获取被删除的属性名和属性值
        String name = event.getName();
        Object value = event.getValue();
        System.out.println(application + "范围内名为"
            + name + ",值为" + value + "的属性被删除了!");
    }
    //当application范围的属性被替换时触发该方法
    public void attributeReplaced(ServletContextAttributeEvent event)
    {
        ServletContext application = event.getServletContext();
        //获取被替换的属性名和属性值
        String name = event.getName();
        Object value = event.getValue();
        System.out.println(application + "范围内名为"
            + name + ",值为" + value + "的属性被替换了!");
    }
}
  • ServletRequestListener: 用于监听用户请求;
  • ServletRequestAttributeListener: 用于监听ServletRequest范围(request)范围内属性的改变;
@WebListener
public class RequestListener
    implements ServletRequestListener , ServletRequestAttributeListener
{
    //当用户请求到达、被初始化时触发该方法
    public void requestInitialized(ServletRequestEvent sre)  
    {
        HttpServletRequest request = (HttpServletRequest)sre.getServletRequest();
        System.out.println("----发向" + request.getRequestURI()
            + "请求被初始化----");    }
    //当用户请求结束、被销毁时触发该方法
    public void requestDestroyed(ServletRequestEvent sre) 
    {
        HttpServletRequest request = (HttpServletRequest)sre.getServletRequest();
        System.out.println("----发向" + request.getRequestURI()
            + "请求被销毁----");
    }
    //当程序向request范围添加属性时触发该方法
    public void attributeAdded(ServletRequestAttributeEvent event) 
    {
        ServletRequest request = event.getServletRequest();
        //获取添加的属性名和属性值
        String name = event.getName();
        Object value = event.getValue();
        System.out.println(request + "范围内添加了名为"
            + name + ",值为" + value + "的属性!");
    }
    //当程序从request范围删除属性时触发该方法
    public void attributeRemoved(ServletRequestAttributeEvent event)
    {
        ServletRequest request = event.getServletRequest();
        //获取被删除的属性名和属性值
        String name = event.getName();
        Object value = event.getValue();
        System.out.println(request + "范围内名为"
            + name + ",值为" + value + "的属性被删除了!");
    }
    //当request范围的属性被替换时触发该方法
    public void attributeReplaced(ServletRequestAttributeEvent event)
    {
        ServletRequest request = event.getServletRequest();
        //获取被替换的属性名和属性值
        String name = event.getName();
        Object value = event.getValue();
        System.out.println(request + "范围内名为"
            + name + ",值为" + value + "的属性被替换了!");
    }
}
  • HttpSessionListener: 用于监听用户session的开始和结束;
  • HttpSessionAttributeListener: 用于舰艇和HttpSession范围(session)内属性的改变;
@WebListener
public class OnlineListener 
    implements HttpSessionListener
{
    //当用户与服务器之间开始session时触发该方法
    public void sessionCreated(HttpSessionEvent se) 
    {
        HttpSession session = se.getSession();
        ServletContext application = session.getServletContext();
        //获取session ID
        String sessionId = session.getId();
        //如果是一次新的会话
        if (session.isNew())
        {
            String user = (String)session.getAttribute("user");
            //未登录用户当游客处理
            user = (user == null) ? "游客" : user;
            Map online = (Map)
                application.getAttribute("online");
            if (online == null)
            {
                online = new Hashtable();
            }
            //将用户在线信息放入Map中
            online.put(sessionId , user);
            application.setAttribute("online" , online);
        }
    }
    //当用户与服务器之间session断开时触发该方法
    public void sessionDestroyed(HttpSessionEvent se)
    {
        HttpSession session = se.getSession();
        ServletContext application = session.getServletContext();
        String sessionId = session.getId();
        Map online = (Map)
            application.getAttribute("online");
        if (online != null)
        {
            //删除该用户的在线信息
            online.remove(sessionId);
        }
        application.setAttribute("online" , online);
    }
}
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title> 用户在线信息 title>
    <meta name="website" content="http://www.crazyit.org" />
head>
<body>
在线用户:
<table width="400" border="1">
<%
Map<String , String> online = (Map<String , String>)application
    .getAttribute("online");
for (String sessionId : online.keySet())
{%>
<tr>
    <td><%=sessionId%>
    <td><%=online.get(sessionId)%>
tr>
<%}%>
body>
html>
@WebListener
public class RequestListener
    implements ServletRequestListener
{
    //当用户请求到达、被初始化时触发该方法
    public void requestInitialized(ServletRequestEvent sre)  
    {
        HttpServletRequest request = (HttpServletRequest)
            sre.getServletRequest();
        HttpSession session = request.getSession();
        //获取session ID
        String sessionId = session.getId();
        //获取访问的IP和正在访问的页面
        String ip = request.getRemoteAddr(); 
        String page = request.getRequestURI();
        String user = (String)session.getAttribute("user");
        //未登录用户当游客处理
        user = (user == null) ? "游客" : user;
        try
        {
            DbDao dd = new DbDao("com.mysql.jdbc.Driver"
                , "jdbc:mysql://localhost:3306/online_inf"
                , "root"
                , "32147");
            ResultSet rs = dd.query("select * from online_inf where session_id=?"
                , true , sessionId);
            //如果该用户对应的session ID存在,表明是旧的会话
            if (rs.next())
            {
                //更新记录
                rs.updateString(4, page);
                rs.updateLong(5, System.currentTimeMillis());
                rs.updateRow();
                rs.close();
            }
            else
            {
                //插入该用户的在线信息
                dd.insert("insert into online_inf values(? , ? , ? , ? , ?)",
                    sessionId , user , ip , page , System.currentTimeMillis());
            }
        }
        catch (Exception ex)
        {
            ex.printStackTrace();
        }
    }
    //当用户请求结束、被销毁时触发该方法
    public void requestDestroyed(ServletRequestEvent sre) 
    {
    }
}
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title> 用户在线信息 title>
    <meta name="website" content="http://www.crazyit.org" />
head>
<body>
在线用户:
<table width="640" border="1">
<%
DbDao dd = new DbDao("com.mysql.jdbc.Driver"
    , "jdbc:mysql://localhost:3306/online_inf"
    , "root"
    , "32147");
//查询online_inf表(在线用户表)的全部记录
ResultSet rs = dd.query("select * from online_inf" , false);
while (rs.next())
{%>
<tr>
    <td><%=rs.getString(1)%>
    <td><%=rs.getString(2)%>
    <td><%=rs.getString(3)%>
    <td><%=rs.getString(4)%>
tr>
<%}%>
body>
html>

配置Listener

  • 使用@WebListener修饰Listener实现类;
  • 在web.xml文件中使用
<listener>
    <listener-class>com.lotus.TestListenerlistener-class>
listener>

你可能感兴趣的:(JavaEE)