一、httpServlet
写一个servlet代码一般都是要继承httpServlet 这个类,然后重写里面的方法
但是它有一个特点,根据之前写的代码,我们发现好像没有写main方法也能正常执行。
原因是:这个代码不是直接运行的,而是放到tomcat上运行的
换句话说,tomcat里就有main方法
1.httpServlet的几个主要方法
init方法是初始化操作
service 收到http请求的时候调用(一般会被doGet/doPost替代)
destroy当不在使用httpServlet实例的时候,调用,来销毁实例(释放资源)
以上三个描述了 servlet的声明周期(经典面试题),就是描述一下这三个方法,什么时间干什么事(调用什么方法)。(在实际开发中,很少会用到,一般都是出现在面试题中)
初始化执行init方法,每次收到http请求调用 service方法,结束前执行destroy方法释放资源
除了init方法,其他方法都可以在子类中重写,并且重写后,不用手动调用,tomcat会在何时机自动调用
destroy方法,大概率事执行不到的。一个servlet 不用了,说明tomcat要关闭了
tomcat关闭有两种方式:
1.直接干掉tomcat 进程(比如直接在任务管理器中 结束任务 , 或者直接点 叉关闭),完全来不及调用destroy。
2.通过8005 管理端口,给tomcat 发送一个“停机”指令,这个时候是能执行到destroy的。
但是通常,都是用第一种方式(直接干掉进程)来关闭servlet的。
使用HttpServlet类
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet("/method") //指定路径
public class MethodServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("doPost");//控制台中打印
resp.getWriter().write("doPost");//http的响应内容,显示在浏览器上
}
@Override
protected void doPut(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("doPut");//控制台中打印
resp.getWriter().write("doPut");//http的响应内容,显示在浏览器上
}
protected void doDelete(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("doDelete");//控制台中打印
resp.getWriter().write("doDelete");//http的响应内容,显示在浏览器上
}
}
二、HttpServletRequest类
可以发现HttpServletRequest的方法里面,都是get方法(读方法),没有set方法(写方法)
原因是,当前拿到的HttpServletRequest,这里的数据是来自于客户端发来的。这些数据的内容是已经确定下来了,程序员是不应该修改的。
(这种框架做出了限制,避免了程序员不小心把原有的请求修改坏的情况了)
经常将URI 、URL混着用
URI :统一资源标识符(相当于身份证号)
URL:统一资源定位符(相当于住址)
1)使用HttpServletRequest类的方法
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Enumeration;
@WebServlet("/show")
public class ShowRequestServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//调用上述api,把得到的结果构造成一个字符串,统一返回给客户端
StringBuilder stringBuilder = new StringBuilder();//使用stringBuilder把HTTP请求中的数据记录下来
stringBuilder.append(req.getProtocol());//获取HTTP协议版本
stringBuilder.append("<br>");//html中的换行
stringBuilder.append(req.getMethod());//获取HTTP请求方法(get/post)
stringBuilder.append("<br>");
stringBuilder.append(req.getRequestURI());//获取链接地址
stringBuilder.append("<br>");
stringBuilder.append(req.getContextPath());//获取一级地址
stringBuilder.append("<br>");
stringBuilder.append(req.getQueryString());//获取quary string
stringBuilder.append("<br>");
//获取所有的 header
Enumeration<String> headernames = req.getHeaderNames();
while(headernames.hasMoreElements()){
String key = headernames.nextElement();
String value = req.getHeader(key);
stringBuilder.append(key + ":" + value + "<br>");
}
//返回响应是,一定要做的事情,告诉浏览器,当前是啥类型
resp.setContentType("text/html;charset=utf8");
//将stringBuild中的内容以字符串形式返回到响应中
resp.getWriter().write(stringBuilder.toString());
}
}
如果不写query string这里的a和b,那么这里就是a=1&b=2这里就是null
2)获取Patameter(query string)
query string是url中 ?a=1&b=2 这种格式,是以键值对形式存在的
其中a 和 b 就是键值对的key,是由程序员自定的
前后端交互有三种方式:
一种是query string ,form表单,json格式(主流)
三种都差不多,具体用那种看个人习惯,以及公司既定的代码风格
servlet 天然支持 query string 和 form表单,而json本身是不支持的,但是可以引入第三方库
1.GET请求
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet("/getParameter")
public class GetParameterServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//此处约定:请求中给定的query string 例如:username=zhangsan&password=123
//上述 query string,就会被tomcat 给自动解析成一个 Map 这样的结构
//getParameter 就是在查询 Map<String,String>里的内容
String username = req.getParameter("username");
String password = req.getParameter("password");
//就可以拿到这些内容之后,做一些其他的任意处理
System.out.println("username =" + username);
System.out.println("password =" + password);
resp.setContentType("text/html charset=utf-8");
resp.getWriter().write("ok");
}
}
不写string是这里是null
当写了我们自定义的username和password的时候,这里就能看见显示的query string的内容了
但是有一个需要注意的点:
当传入的query string的时候如果涉及到中文字符,需要用urlencode去进行编码
(如果不进行urlencode编码,有些浏览器可能无法识别,导致一些错误)
encode之后的结果发送给浏览器,浏览器能自动识别并进行urldecode解码
2.POST请求
import com.sun.prism.PresentableState;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet("/postParameter")
public class PostParameterServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//约定:前端构造形如这样的请求:
//POST / postParameter
//Content-Type:x-www-form-urlencoded
//
//username=zhangsan&password=123
//就需要在后端代码中,把body中的值 给拿到
//获取值的方法,仍然是 getParameter
String username = req.getParameter("username");
String password = req.getParameter("password");
System.out.println("username=" + username);
System.out.println("password=" + password);
resp.setContentType("text/html;charset=utf8");
resp.getWriter().write("okk");
}
}
3)引入json的第三方库(jackson)
1.json的第三方库有很多,Jackson是spring官方推荐的库,也被spring集成起来了,对于后期学习spring比较方便
版本没有要求(也没有必要太新,稳定就行 选择2.15.0)
将这个代码点击,复制粘贴到pom.xml里,点击maven的刷新键,完成json第三方库安装
2.使用jackson(一个类,两个方法)
一个类:ObjectMapper 对象映射器
两个方法:
1-把json字符串,映射成一个Java对象。readValue
Request request = objectMapper.readValue(req.getInputStream(),Request.class);//Request.class 类对象(反射)2-把一个Java对象,映射成json字符串 writeValueAsString
String respJson = objectMapper.writeValueAsString(response);网络传输,使用json字符串。Java代码中各种逻辑,使用Java对象。
站在服务器的角度,收到的请求,就是json字符串,就需要把json字符串,先映射成Java对象,
再进行一系列的业务逻辑处理。处理完之后,可能还需要把得到的Java对象,映射会json字符串,并通过响应来返回。
import com.fasterxml.jackson.databind.ObjectMapper;
import com.sun.org.apache.regexp.internal.RE;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
//把 json格式的字符串请求 映射后的 Java对象
class Request{
public String username;
public String password;
}
class Response{
public boolean ok;
}
@WebServlet("/json")
public class JsonParameterServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//此处的约定请求格式如下:
//POST /json
//Content-Type:application/json
//
//{
// username:"zhangsan",
// password:"123"
//}
//此处也约定响应的格式(也按照 json 来组织):
//{
// ok:true
//}
//把请求的 body 按照 json 格式解析成java对象
ObjectMapper objectMapper = new ObjectMapper();
Request request = objectMapper.readValue(req.getInputStream(),Request.class);//Request.class 类对象(反射)
System.out.println("username=" + request.username);
System.out.println("password" + request.password);
Response response = new Response();
response.ok = true;
//把响应对象转成 json 字符串
String respJson = objectMapper.writeValueAsString(response);
resp.setContentType("application/json;charset=utf8");//设置字符集
resp.getWriter().write(respJson);//返回json格式的字符串
}
}
4)总结:如何进行前后端交互?如何获取前端传来的数据?
1.query string ( 使用 getParameter这个方法)
2.form表单 ( 使用 getParameter这个方法)
3.json(实际常用,导入json 的库 jackson,使用objectMapper对象和json方法)
三、HttpServletResponse类
主要方法
1)setStatus设置状态码 和 sendError 设置状态码同时设置body返回的内容
1.setStatus设置状态码
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet("/Status")
public class StatusServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setStatus(404);//设置状态码为404 not found 找不到
}
}
光有状态码,body里面没有内容,是空的,对用户不太友好,浏览器里什么内容也没有,不知道到底出现了什么问题
2.sendError 设置状态码同时设置body返回的内容
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet("/Status")
public class StatusServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// resp.setStatus(404);//设置状态码为404 not found 找不到
resp.sendError(404,"哎呀~网页找不到啦~是不是出现问题啦?");
}
}
可以看到设置了状态码404 同时还设置了 提示内容
这个页面就是sendError生成的
2)通过setHeader属性,给响应中设置一些特殊的header
1.设置 refresh:1,让浏览器每秒刷新一次
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet("/refresh")
public class RefreshServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setHeader("refresh","1");//refresh浏览器刷新,1为时间,每一秒刷新一次
resp.getWriter().write(" "+System.currentTimeMillis());//在浏览器显示当前时间
}
}
观察发现好像每次并没有精确1s刷新,可能是一秒多一点
原因是:浏览器响应也需要时间,所以比原有的1s多一些
2.构造重定向响应
1-状态码是 3开头(例如:302)
2-header 需要有一个Location属性,描述要跳转到哪里
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet("/redirect")
public class RedirectServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//方法一
resp.setStatus(302);
resp.setHeader("Location","http://www.baidu.com");//重定向/redirect这个网页到 www.baidu.com
//方法二
resp.sendRedirect("http://www.baidu.com");
//两者效果一致
}
}
(这几个类学完,就可以愉快的进行接下来的简单网站啦~~)