JavaWeb------request and response
Servlet体系结构
Servlet概念
- 狭义Servlet是指Java语言中的一个接口,而广义的Servlet是指任何实现Servlet接口的类。
- Servlet绝大多数情况下是用来扩展基于HTTP协议的的Web服务器
Servlet生命周期
Init()、service()、destroy()是Servlet生命周期的主要方法,代表了整个Servlet运行的过程。
- 当程序运行之后,会创建出一个Servlet实例对象。
- Servlet实例对象会首先执行init()方法进行初始化的过程。该方法只会运行一次。
- 执行完init()方法之后,Servlet对象会执行service()方法进行工作,后续都只会执行该方法。
- 当Servlet对象执行完毕之后,它会调用destroy()方法进行销毁。
Servlet继承关系
Class GenericServlet implement Servlet
public abstract class GenericServlet implements Servlet, ServletConfig, Serializable {
private static final String LSTRING_FILE = "javax.servlet.LocalStrings";
private static ResourceBundle lStrings = ResourceBundle.getBundle("javax.servlet.LocalStrings");
private transient ServletConfig config;
public GenericServlet() {
}
public void destroy() {
}
public String getInitParameter(String name) {
ServletConfig sc = this.getServletConfig();
if (sc == null) {
throw new IllegalStateException(lStrings.getString("err.servlet_config_not_initialized"));
} else {
return sc.getInitParameter(name);
}
}
public Enumeration<String> getInitParameterNames() {
ServletConfig sc = this.getServletConfig();
if (sc == null) {
throw new IllegalStateException(lStrings.getString("err.servlet_config_not_initialized"));
} else {
return sc.getInitParameterNames();
}
}
public ServletConfig getServletConfig() {
return this.config;
}
public ServletContext getServletContext() {
ServletConfig sc = this.getServletConfig();
if (sc == null) {
throw new IllegalStateException(lStrings.getString("err.servlet_config_not_initialized"));
} else {
return sc.getServletContext();
}
}
public String getServletInfo() {
return "";
}
public void init(ServletConfig config) throws ServletException {
this.config = config;
this.init();
}
public void init() throws ServletException {
}
public void log(String msg) {
this.getServletContext().log(this.getServletName() + ": " + msg);
}
public void log(String message, Throwable t) {
this.getServletContext().log(this.getServletName() + ": " + message, t);
}
public abstract void service(ServletRequest var1, ServletResponse var2) throws ServletException, IOException;
public String getServletName() {
ServletConfig sc = this.getServletConfig();
if (sc == null) {
throw new IllegalStateException(lStrings.getString("err.servlet_config_not_initialized"));
} else {
return sc.getServletName();
}
}
}
以上代码是GenericServlet的源码,从代码可以我们看出,GenericServlet类中包含了无参的init()方法和无参的destroy()方法所以当我们定义了一个类继承了GenericServlet类的时候,只需要覆盖重写Service()方法。
HttpServlet
public abstract class HttpServlet extends GenericServlet implements Serializable {
private static final String METHOD_DELETE = "DELETE";
private static final String METHOD_HEAD = "HEAD";
private static final String METHOD_GET = "GET";
private static final String METHOD_OPTIONS = "OPTIONS";
private static final String METHOD_POST = "POST";
private static final String METHOD_PUT = "PUT";
private static final String METHOD_TRACE = "TRACE";
private static final String HEADER_IFMODSINCE = "If-Modified-Since";
private static final String HEADER_LASTMOD = "Last-Modified";
private static final String LSTRING_FILE = "javax.servlet.http.LocalStrings";
private static ResourceBundle lStrings = ResourceBundle.getBundle("javax.servlet.http.LocalStrings");
public HttpServlet() {
}
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String protocol = req.getProtocol();
String msg = lStrings.getString("http.method_get_not_supported");
if (protocol.endsWith("1.1")) {
resp.sendError(405, msg);
} else {
resp.sendError(400, msg);
}
}
protected long getLastModified(HttpServletRequest req) {
return -1L;
}
protected void doHead(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
NoBodyResponse response = new NoBodyResponse(resp);
this.doGet(req, response);
response.setContentLength();
}
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String protocol = req.getProtocol();
String msg = lStrings.getString("http.method_post_not_supported");
if (protocol.endsWith("1.1")) {
resp.sendError(405, msg);
} else {
resp.sendError(400, msg);
}
}
protected void doPut(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String protocol = req.getProtocol();
String msg = lStrings.getString("http.method_put_not_supported");
if (protocol.endsWith("1.1")) {
resp.sendError(405, msg);
} else {
resp.sendError(400, msg);
}
}
protected void doDelete(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String protocol = req.getProtocol();
String msg = lStrings.getString("http.method_delete_not_supported");
if (protocol.endsWith("1.1")) {
resp.sendError(405, msg);
} else {
resp.sendError(400, msg);
}
}
private Method[] getAllDeclaredMethods(Class<?> c) {
if (c.equals(HttpServlet.class)) {
return null;
} else {
Method[] parentMethods = this.getAllDeclaredMethods(c.getSuperclass());
Method[] thisMethods = c.getDeclaredMethods();
if (parentMethods != null && parentMethods.length > 0) {
Method[] allMethods = new Method[parentMethods.length + thisMethods.length];
System.arraycopy(parentMethods, 0, allMethods, 0, parentMethods.length);
System.arraycopy(thisMethods, 0, allMethods, parentMethods.length, thisMethods.length);
thisMethods = allMethods;
}
return thisMethods;
}
}
protected void doOptions(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
Method[] methods = this.getAllDeclaredMethods(this.getClass());
boolean ALLOW_GET = false;
boolean ALLOW_HEAD = false;
boolean ALLOW_POST = false;
boolean ALLOW_PUT = false;
boolean ALLOW_DELETE = false;
boolean ALLOW_TRACE = true;
boolean ALLOW_OPTIONS = true;
for(int i = 0; i < methods.length; ++i) {
Method m = methods[i];
if (m.getName().equals("doGet")) {
ALLOW_GET = true;
ALLOW_HEAD = true;
}
if (m.getName().equals("doPost")) {
ALLOW_POST = true;
}
if (m.getName().equals("doPut")) {
ALLOW_PUT = true;
}
if (m.getName().equals("doDelete")) {
ALLOW_DELETE = true;
}
}
String allow = null;
if (ALLOW_GET) {
allow = "GET";
}
if (ALLOW_HEAD) {
if (allow == null) {
allow = "HEAD";
} else {
allow = allow + ", HEAD";
}
}
if (ALLOW_POST) {
if (allow == null) {
allow = "POST";
} else {
allow = allow + ", POST";
}
}
if (ALLOW_PUT) {
if (allow == null) {
allow = "PUT";
} else {
allow = allow + ", PUT";
}
}
if (ALLOW_DELETE) {
if (allow == null) {
allow = "DELETE";
} else {
allow = allow + ", DELETE";
}
}
if (ALLOW_TRACE) {
if (allow == null) {
allow = "TRACE";
} else {
allow = allow + ", TRACE";
}
}
if (ALLOW_OPTIONS) {
if (allow == null) {
allow = "OPTIONS";
} else {
allow = allow + ", OPTIONS";
}
}
resp.setHeader("Allow", allow);
}
protected void doTrace(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String CRLF = "\r\n";
String responseString = "TRACE " + req.getRequestURI() + " " + req.getProtocol();
String headerName;
for(Enumeration reqHeaderEnum = req.getHeaderNames(); reqHeaderEnum.hasMoreElements(); responseString = responseString + CRLF + headerName + ": " + req.getHeader(headerName)) {
headerName = (String)reqHeaderEnum.nextElement();
}
responseString = responseString + CRLF;
int responseLength = responseString.length();
resp.setContentType("message/http");
resp.setContentLength(responseLength);
ServletOutputStream out = resp.getOutputStream();
out.print(responseString);
}
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String method = req.getMethod();
long lastModified;
if (method.equals("GET")) {
lastModified = this.getLastModified(req);
if (lastModified == -1L) {
this.doGet(req, resp);
} else {
long ifModifiedSince = req.getDateHeader("If-Modified-Since");
if (ifModifiedSince < lastModified) {
this.maybeSetLastModified(resp, lastModified);
this.doGet(req, resp);
} else {
resp.setStatus(304);
}
}
} else if (method.equals("HEAD")) {
lastModified = this.getLastModified(req);
this.maybeSetLastModified(resp, lastModified);
this.doHead(req, resp);
} else if (method.equals("POST")) {
this.doPost(req, resp);
} else if (method.equals("PUT")) {
this.doPut(req, resp);
} else if (method.equals("DELETE")) {
this.doDelete(req, resp);
} else if (method.equals("OPTIONS")) {
this.doOptions(req, resp);
} else if (method.equals("TRACE")) {
this.doTrace(req, resp);
} else {
String errMsg = lStrings.getString("http.method_not_implemented");
Object[] errArgs = new Object[]{method};
errMsg = MessageFormat.format(errMsg, errArgs);
resp.sendError(501, errMsg);
}
}
private void maybeSetLastModified(HttpServletResponse resp, long lastModified) {
if (!resp.containsHeader("Last-Modified")) {
if (lastModified >= 0L) {
resp.setDateHeader("Last-Modified", lastModified);
}
}
}
public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
HttpServletRequest request;
HttpServletResponse response;
try {
request = (HttpServletRequest)req;
response = (HttpServletResponse)res;
} catch (ClassCastException var6) {
throw new ServletException("non-HTTP request or response");
}
this.service(request, response);
}
}
以上是HttpServlet类的源码,从源码中我们可以发现,HttpServlet抽象类继承自GenericServlet类。其中有俩个方法doPost()方法和doGet()方法,当我们定义了一个类,继承了该抽象类,就需要我们重写其中的俩个方法。例如下面的代码:
public class HttpServlet1 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
}
}
定义完成之后,配置Servlet有俩种方式
1. 我们可以在web.xml中进行配置
<servlet> //servlet用来声明一个Servlet
<servlet-name>HelloServlet</servlet-name> //用来定义servlet的名称
<servlet-class>mypack.HelloServlet</servlet-class> //用来指定servlet的完全限定的名称。
</servlet>
<servlet-mapping> //将URL模式映射到某个Servlet,即该Servlet处理的URL。
<servlet-name>HelloServlet</servlet-name> //Servlet的名字,跟上面一致
<url-pattern>/hello</url-pattern> //指定相对于Servlet的URL的路径
</servlet-mapping>
2. 可以在Servlet类中用@WebServlet Annotation进行配置
@WebServlet("/demo3")
Request概念介绍
Request是指在BS架构中,客户端浏览器向服务器发送一次请求
Request常用方法介绍
获取HTTP中请求头数据
String getHeader(String name):通过请求头的名称获取请求头的值
Enumeration<String> getHeaderNames()获取所有请求头名称
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//1.获取所有的请求头
Enumeration<String> headerNames = request.getHeaderNames();
//2.遍历
while(headerNames.hasMoreElements()){
String name = headerNames.nextElement();
//根据名称获取请求头的值
String value = request.getHeader(name);
System.out.println(name+"---"+value);
}
//获取请求头数据:user-agent
String agent = request.getHeader("user-agent");
//判断agent的浏览器版本
if(agent.contains("Chrome")){
System.out.println("谷歌");
}else if(agent.contains("Firefox")){
System.out.println("火狐");
}
//获取请求头数据:referer
String referer = request.getHeader("referer");
System.out.println(referer);
}
获取请求行常用方法
1. 获取请求方式:String getMethod()
2. 获取虚拟目录: String getContextPath()
3. 获取Servlet路径: String getServletPath()
4. 获取get方式请求参数: String getQueryString()
5. 获取请求URI:String getRequestURI() 、StringBuffer getRequestURL()
6. 获取协议及版本:String getProtocol()
7. 获取客户机的IP地址:String getRemoteAddr()
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//1.获取请求方式:GET
String method = request.getMethod();
System.out.println(method);
//2.获取虚拟目录 /dat14
String contextPath = request.getContextPath();
System.out.println(contextPath);
//3.获取Servlet路径 /demo1
String servletPath = request.getServletPath();
System.out.println(servletPath);
// 4.获取get方式请求参数:name=zhangsan
String queryString = request.getQueryString();
System.out.println(queryString);
//5.1获取请求URI:/day14/demo1
//5.2 StringBuffer getRequestURL()
String requestURI = request.getRequestURI();
StringBuffer requestURL = request.getRequestURL();
System.out.println(requestURI);
System.out.println(requestURL);
//6.获取协议及版本:HTTP/1.1
String protocol = request.getProtocol();
System.out.println(protocol);
//7.获取客户机的IP地址:
String remoteAddr = request.getRemoteAddr();
System.out.println(remoteAddr);
}
获取请求体数据
获取流对象:
BufferedReader getReader():获取字符输入流,只能操作字符数据
ServletInputStream getInputStream():获取字节输入流,可以操作所有类型的数据
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//获取请求消息体
//1.获取字符流
BufferedReader br = request.getReader();
//2.读取数据
String line = null;
while((line=br.readLine())!=null){
System.out.println(line);
}
}
其他功能
1.获取请求参数通用方式
String getParameter(String name) 根据参数名称获取参数值 username=zs&&password=123
String[] getParameterValues(String name) 根据参数名称获取参数值的数组 hobby=game&&hobby=ball
Enumeration<String> getParameterNames() 获取所有请求的参数名称
Map<String, String[]> getparameterMap() 获取所有参数的map集合
2.请求转发:一种在服务器内部的资源跳转方式
步骤:
1.通过request对象获取请求转发器对象 RequestDispatcher getRequestDispatcher(String path)
2.使用RequestDispatcher对象来进行转发
forward(request,response)
特点:浏览器地址栏路径(url)不发生变化
只能转发到当前服务器内部资源中
转发只是一次请求
3.共享数据:
域对象:一个有作用范围的对象,可以在范围内共享数据
request域:代表一次请求的范围,一般用于请求转发的多个资源中共享数据
方法:
1.setAttribute(String name,Object obj):存储数据
2.Object getAttitude(String name):通过键获取值
3.void removeAttribute(String name):通过键移除键值对
4.获取ServletContext
ServletContext getServletContext()
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//出现乱码问题是设置请求request编码
//request.setCharacterEncoding("utf-8");
//post 获取请求参数
//根据参数名称获取参数值
String username = request.getParameter("username");
// System.out.println(username);
//根据参数名称获取参数值的数组
String[] hobbies = request.getParameterValues("hobby");
for (String hobby:hobbies
) {
System.out.println(hobby);
}
//获取所有请求的参数名称
Enumeration<String> parameterNames = request.getParameterNames();
while(parameterNames.hasMoreElements()){
String name = parameterNames.nextElement();
System.out.println(name);
String value = request.getParameter(name);
System.out.println(value);
System.out.println("-------------------");
}
//获取所有参数的map集合
Map<String, String[]> parameterMap = request.getParameterMap();
//遍历
Set<String> keyset = parameterMap.keySet();
for (String name:keyset
) {
//根据键获取值
String[] values = parameterMap.get(name);
System.out.println(name);
for (String value:values
) {
System.out.println(value);
}
System.out.println("--------------");
}
}
Response概念介绍
在BS架构中,服务器给客户端浏览器反馈结果。
常见的状态码
状态码 | 说明 |
---|---|
200 | 访问成功 |
302 | 资源重定向 |
304 | 访问缓存 |
404 | 请求路径没有对应资源 |
405 | 请求方式没有对应doPost或doGet方法 |
500 | 服务器内部出现异常 |
重定向
重定向和转发的区别
重定向 response.sendDedirect():
1.地址栏发生变化
2.至少请求了俩次,切不能使用request对象共享数据
3.重定向可以访问其他站点(服务器)资源
转发 request.getRequestDispatcher()
1.地址栏不变
2.转发只是一次请求,可以用request对象来共享资源
3.转发只能访问当前服务器下的资源
重定向的方法
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("ziyuan1....");
//访问ziyuan1,会自动跳转到ziyuan2
//1.设置状态码为3.2
// response.setStatus(302);
//2.设置响应头location
// response.setHeader("location","/ziyuan2");
//动态获取虚拟目录
String contextPath = request.getContextPath();
//简单的重定向方法
response.sendRedirect(contextPath+"/ziyuan2");
}
Response常见方法
输出字符数据
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
/*
设置编码的方法
//获取流对象之前,设置流的默认编码:ISO-8859-01 设置为:GBK
//response.setCharacterEncoding("utf-8");
//告诉浏览器,服务器发送的消息体数据的编码,建议浏览器使用该编码来解码
//response.setHeader("content-type","text/html;charset=utf-8")
*/
//简单的形式来设置编码,作用同setHeader()
response.setContentType("text/html;charset=utf-8");
//1.获取字符输出流
PrintWriter pw = response.getWriter();
//2.输出数据
pw.write("你好,hello response");
}
输出字节数据
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html;charset=utf-8");
//1.获取字节输出流
ServletOutputStream sos = response.getOutputStream();
//2.输出数据 hello是字符,getBytes()是获取字节数组
sos.write("hello.".getBytes("utf-8"));
}
声明
本文是作者在学习JavaWeb中的一些笔记,希望能够帮助到大家。作者才疏学浅,若有错误,欢迎批评指正。