Servlet

  • server + let,运行在服务器端的小程序。
  • Servlet实际就是一个接口,广义上我们认为凡是实现Servlet接口的类,我们都称他是一个Servlet。
  • 要继承HttpServlet类,必须检查项目->构建路径->库里里面有没有tomcat的jar包。
  • 作用:接收用户发送的请求;调用其他的java程序来处理请求;返回一个页面给用户。
  • 实现步骤:
  1. 创建一个类并实现Servlet接口。
  2. 重写doGet()和doPost(),doGet交给doPost处理,第一句:改编码(utf-8不行就gbk)。
  3. 在web.xml中配置servlet,否则请求和处理无法关联:

    <servlet>
        <!--Servlet的别名,以后通过别名查询该Servlet-->
        <servlet-name>唯一别名</servlet-name>
        <!--服务器通过全类名创建Servlet的实例-->
        <servlet-class>全类名</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>别名</servlet-name>
        <!--Servlet映射的请求地址,用户通过该地址访问Servlet-->
        <url-pattern>需要servlet处理的请求地址</url-pattern>
    </servlet-mapping>
    
  • 入门项目:HeadFirstServletChap05

Servlet的生命周期

  1. 构造器
  • 启动的时候就会加载Servlet类,第一次处理请求的时候就会实例化,即调用构造器;且只会调用一次,因为Servlet是单例模式,以多线程的方式调用service(),但Servlet不是线程安全的,所以尽量不要在service()中操作全局变量。
  1. init()
  • 构造器调用后马上调用init(),init只执行一次,里面可以写一些初始化的东西,然后你请求的话它就会有doGet、doPost的服务。
  1. service()
  • Servlet每次处理请求时都会调用service(),用于处理请求,会调用多次。
  1. destroy()
  • Servlet对象销毁前(web项目卸载时)调用,用来做一些收尾工作,释放资源等。
  • 销毁情况有好几种:长时间不用(等半天)servlet,自动销毁;关闭的时候也销毁(即释放内存,销毁掉之后再访问则重新调用init)

  • servlet是单实例多线程,使用时要注意安全性。

  • 代码实例:HeadFirstServletChap05->com.java1234.web包->LifeServlet.java

ServletConfig

  • 每一个servlet都有一个唯一的ServletConfig对象,表示当前servlet的配置信息。
  • 由tomcat服务器创建,最终作为参数传递到init()中,可以在init()中直接使用。
  • 当我们通过继承HttpServlet创建servlet实现类时,父类已经实现ServletConfig接口,所以我们可以直接在类中调用ServletConfig的方法。
  • 作用:获取Servlet的别名;获取servlet的初始化参数;获取当前web应用的ServletContext对象。

    <servlet>
        <servlet-name>AServlet</servlet-name>
        <servlet-class>com.atguigu.servlet.AServlet</servlet-class>
        <init-param>
            <param-name>user</param-name>
            <param-value>root</param-value>
        </init-param>
        <init-param>
            <param-name>password</param-name>
            <param-value>123123</param-value>
        </init-param>
    </servlet>
    

ServletContext

  • 一个web应用对应唯一的ServletContext对象,表示当前的web应用。
  • 项目启动时创建,卸载时销毁。
  • ServletConfig.getServletContext():获取ServletContext对象。
  • 作用:获取整个web应用的初始化参数,如

    <context-param>
        <param-name>phone</param-name>
        <param-value>1388888888</param-value>
    </context-param>
    

    获取资源的真实路径(主要用于文件上传、下载);可以作为一个域对象再不同的web资源之间共享数据。

GenericServlet

  • 实现了Servlet接口,是通用的servlet父类。

HttpServlet

  • 继承自GenericServlet。
  • 重写了service():
  1. 将入参ServletRequest和ServletResponse强转为Http
  • 一般继承HttpServlet来实现自定义Servlet。

  • 客户端跳转的话request里存放的数据不会被传过去,但是session、application可以。

  • 代码实例:HeadFirstServletChap05->com.java1234.web包->RedirectServlet.java

  • 服务器跳转是内部转发的,跟客户端的唯一不同是:不是调用重定向,而是调用getRequestDispatcher(“target.jsp”).forward(request, response);其他存值什么的操作都一样

  • 服务器跳转能获取request值
  • 代码实例:HeadFirstServletChap05->com.java1234.web包->ForwardServlet.java

HttpServletRequest和ServletRequest的区别

  • servlet可以处理多种形式的请求响应,而http只是其中一种,所以HttpServletRequest是ServletRequest的子接口,它多了一些针对HTTP协议的方法:
getHeader(String name)
getMethod()
getSession() 
...

request与response简介

  • 当web服务器收到客户端的一次HTTP请求时,会创建一个代表请求的request对象和代表响应的response对象。所以我们要获取客户机提交过来的数据,找request,要向客户端输出数据,找response。

request获取当前请求

/*当前页面请求:http://localhost:8080/thz-manager-web/forgetPwd_check(无参数)*/

String path = request.getContextPath(); // 一般是项目名:/thz-manager-web

//根路径
String basePath = request.getScheme()+"://" //协议:http
        +request.getServerName()+":" //服务主机:localhost
        +request.getServerPort() //端口号:8080
        +path+"/";

String remoteAddress=request.getRemoteAddr(); //发起请求的客户端ip--0:0:0:0:0:0:0:1

String servletPath=request.getServletPath(); //请求路径:/forgetPwd_check

/**虚拟目录映射为实际目录*/
//String realPath=request.getRealPath("/"); //不推荐使用
//推荐使用:request.getSession().getServletContext().getRealPath("url")
//得到工程文件在服务器中的实际路径,即绝对路径
String realPath=request.getSession().getServletContext().getRealPath("/"); //映射/为实际目录
//D:\ideaProjects\thz\thz-parent\thz-manager-web\src\main\webapp\
String pagePath=request.getSession().getServletContext().getRealPath("./"); 
//网页所在目录:D:\ideaProjects\thz\thz-parent\thz-manager-web\src\main\webapp\.
//(放在后台不是很合适,应该是写在前端脚本)

String remoteUser=request.getRemoteUser(); //一般得到null

//得到相对路径的url:/thz-manager-web/forgetPwd_check
String requestURI=request.getRequestURI(); 
//完整路径:http://localhost:8080/thz-manager-web/forgetPwd_check
StringBuffer requestURL=request.getRequestURL(); 

String queryString=request.getQueryString(); //获取请求参数串,无则为null

//完整请求:http://localhost:8080/thz-manager-web/forgetPwd_checknull
String fullPath=requestURL+queryString; 

String method=request.getMethod(); //获取请求方法,POST/GET等

response.getwriter()和response.getOutputStream()

  • getWriter():向客户端输出字符型数据,是字符流。
  • getOutputStream(): 向客户端输出二进制数据,是字节流,返回ServletOutputStream对象,提供一个二进制输出流给客户端。
  1. 使用OutputStream输出中文数据:在服务端,输出数据的编码要和客户端使用的编码一致,如,客户端浏览器使用utf-8,则
outputStream.write("中文".getBytes("UTF-8")); //getBytes()返回byte[]
  • 那么在服务端如何控制客户端以utf-8解码数据呢?可以设置响应头控制浏览器的行为,如:
response.setHeader("content-type", "text/html;charset=UTF-8");
  • 完整示例:
String str="我心自在";
response.setHeader("content-type", "text/html;charset=UTF-8");
OutputStream os=response.getOutputStream();
//字符转字节;编码默认根据系统环境获取
byte[]b=str.getBytes("utf-8");
os.write(b);
  1. 使用getWriter()输出中文数据:推荐,比前者节省了字符转字节这一步骤。
String str="我心自在";
//1. 设置字符以何种编码输出到浏览器
response.setCharacterEncoding("utf-8");
//2. 获取PrintWriter输出流
PrintWriter pw=response.getWriter();
pw.write(str);
pw.close();
  • 上述两个步骤不能颠倒,一定要在获取输出流前设置编码,否则设置将无效,浏览器乱码。