在实际使用servlet的过程中,一般不推荐直接实现servlet接口,可以通过继承servlet接口的子类,重写其中的方法进行扩展开发,避免一些无用方法。 例如:直接继承HttpServlet
并且在servlet3.0之后,为了简化servlet开发,servlet 3.0提供了注解的方式简化servlet的配置。 例如: Servlet请求API-HttpServletRequest 设置参数编码 相关API
package com.bjsxt.servlet; import java.io.IOException; import java.util.Arrays; import java.util.Collections; import java.util.Enumeration; import java.util.List; import java.util.Map; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @WebServlet("/api.do")// 赋值给了 value 和 urlPatterns 等价 public class ServletApi extends HttpServlet { private static final long serialVersionUID = 782338046693469415L; @Override protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //设置处理请求数据的编码 req.setCharacterEncoding("UTF-8"); //doParam(req,resp); //doNetInfo(req,resp); forward(req,resp); } /** * @Title: doParam * @author: james * @date: 2020年6月30日 上午11:15:26 * @Description: 处理请求参数 * @param req * @param resp * @throws ServletException * @throws IOException * @return: void */ protected void doParam(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //getParameter(参数名) : 根据参数名 获取请求参数对应的值 System.out.println("文本:"+req.getParameter("username")); System.out.println("密码框值:"+req.getParameter("password")); System.out.println("单选:"+req.getParameter("sex")); System.out.println("下拉:"+req.getParameter("city")); System.out.println("复选:"+req.getParameter("like")); //getParameterValues(name) : 根据名称 获取对应的值 值是字符串数组 用于获取复选框的值 String[] strs = req.getParameterValues("like"); List<String> list = Arrays.asList(strs); System.out.println("复选:"+list); //getParameterMap() : 获取请求参数信息 将参数名作为key 参数值是字符串数组 //复选框 在传递时 是一个name 对应多个值,为了兼容所以值使用字符串数组 Map<String, String[]> parameterMap = req.getParameterMap(); System.out.println(parameterMap); System.out.println("----------------------------"); //getParameterNames() : 获取所有请求参数的名称 Enumeration<String> names = req.getParameterNames(); while(names.hasMoreElements()) { System.out.println(names.nextElement()); } //getPart(name) : 根据名称 获取part 对应的数据信息 一般用于非文本信息数据 用于文件上传 //getParts() : 获取所有的数据信息 } /** * @Title: doNetInfo * @author: james * @date: 2020年6月30日 上午11:35:58 * @Description: 获取网络信息 * @param req * @param resp * @throws ServletException * @throws IOException * @return: void */ protected void doNetInfo(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //getMethod() 获取请求方法 GET POST DELETE PUT 等等 System.out.println(req.getMethod()); //getLocalPort() 获取端口 System.out.println(req.getLocalPort()); //getProtocol() 获取协议 System.out.println(req.getProtocol()); //getRequestURL() 获取请求的url System.out.println(req.getRequestURL()); //getRequestURI() 获取资源路径 System.out.println(req.getRequestURI()); //获取请求头 //请求数据类型 System.out.println(req.getContentType()); //req.getHeader(name) 获取指定的请求头 System.out.println(req.getHeader("Accept-Language")); } /** * @Title: setEncoding * @author: Mr.T * @date: 2020年6月30日 上午11:44:08 * @Description: 设置处理请求的字符编码 * 在servlet中,处理请求的数据只会处理一次,且tomcat 8.0以上 get请求按照UTF-8编码处理 * post请求按照默认的编码 : ISO-8859-1 处理,tomcat 8.0 以下get和post请求都使用 ISO-8859-1 处理 * 如果请求参数有汉字,则使用setCharacterEncoding进行编码设置 * 注意,设置编码一定要在getParameter方法前面进行设置 * * * @param req * @param resp * @throws ServletException * @throws IOException * @return: void */ protected void setEncoding(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { req.setCharacterEncoding("UTF-8"); } /** * @Title: forward * @author: james * @date: 2020年6月30日 上午11:56:05 * @Description: 内部转发 * 内部转发,是指当前程序不处理当前请求 而是将当前请求转发到下一个程序让其处理。 * 这种形式可以实现跳转的效果的。但是不推荐使用。 * 内部转发时,会将当前的request、response对象信息传递给指定的转发地址 * 内部转发是服务器内部进行程序调用,所以浏览器上面的url地址不会发生改变 * 由于内部转发浏览器上的url地址不会发生改变,那么一旦浏览器刷新,之前所有关联的 * 业务代码会重复执行一次,这样会加大服务器压力,也可能造成数据异常。 * @param req * @param resp * @throws ServletException * @throws IOException * @return: void */ protected void forward(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //getRequestDispatcher("需要将请求转发的地址") //forward(req,resp) :进行转发 System.out.println("servlet api"); req.getRequestDispatcher("servlet04.do").forward(req, resp); } /** * @Title: doScope * @author: james * @date: 2020年7月1日 上午9:06:23 * @Description: 作用域相关方法 * 什么是作用域:起作用的范围 * 作用域对象: * 在Javaweb中,作用域分为4类: * 当前页面 :当前页面pageContext page * 当前请求 : 一次请求 request * 当前会话 : 一次会话 ,指客户端与服务器的多次应答。默认一次会话时间没有断开过的话是30分钟。每次会话开启服务器会给一个标识符给客户端 * 客户端会将这个标识符下次请求时,带给服务器,这样同样的标识符的请求就是同一次会话。 session * 当前应用 : 每个应用程序,在启动的时候就会创建一个全局的容器,标识是当前应用的容器。这个容器有且只有一个 application * 以上4个作用域,pageContext作用域只有JSP存在 * @param req * @param resp * @throws ServletException * @throws IOException * @return: void */ protected void doScope(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //获取其他作用域对象 //获取session HttpSession session = req.getSession();//每个请求都有个关联的session //获取application ServletContext context = req.getServletContext(); //作用域中公共方法 //setAttribute(name, o) : 向作用域存放数据 K-V形式 req.setAttribute("name", "韩梅梅"); req.setAttribute("age", 18); //getAttribute(name) : 根据name 从作用域中获取值 System.out.println(req.getAttribute("name")); //getAttributeNames() : 获取作用域中所有的name值 Enumeration<String> attributeNames = req.getAttributeNames(); System.out.println("----------------------------"); while(attributeNames.hasMoreElements()) { System.out.println(attributeNames.nextElement()); } //删除作用域中的值 req.removeAttribute("name"); } }Servlet响应API-HttpServletResponse 相关API
/** * @Title: doRespHeader * @author: Mr.T * @date: 2020年7月1日 上午9:25:28 * @Description: 响应头相关方法 * @param req * @param resp * @throws ServletException * @throws IOException * @return: void */ protected void doRespHeader(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //设置自定义的响应头 resp.addHeader("zhangsan", "李四"); //设置响应的编码 resp.setCharacterEncoding("UTF-8"); //设置响应的数据的类型 resp.setContentType("text/html;charset=utf-8"); //获取响应流中字符串 //PrintWriter writer = resp.getWriter(); //writer.print("Hello 客户端"); //writer.flush(); //获取响应数据的字节流 //字节流 和 字符流区别 :字节流处理的数据单位是字节 字符流处理数据的单位是字符 /** * 一般而言 字符流适合处理文本数据 * 字节流适合处理文件数据: 音频 视频 其他文件等等。 */ ServletOutputStream os = resp.getOutputStream(); String str = "不要歧视我,我是字符流的爹!"; os.write(str.getBytes()); os.flush(); } /** * @Title: redirect * @author: james * @date: 2020年7月1日 上午9:49:07 * @Description: 重定向 * 是指服务器通知浏览器,重新请求的地址。 * 这种方式也能实现跳转的效果 * @param req * @param resp * @throws ServletException * @throws IOException * @return: void */ protected void redirect(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //通知浏览器 重定向到 index.html //通知浏览器 你去请求 index.html 这个地址 resp.sendRedirect("https://www.baidu.com"); }重定向和内部转发的比较
重定向和内部转发都能实现页面刷新。 但是重定向是浏览器重新请求,内部转发是上服务器内部让新的程序协助原程序处理当前的请求。相较而言,重定向是多次请求,而内部转发是一次请求。重定向会产生多个请求对象,内部转发则是同一个请求对象,而request对象又是一个作用域对象,使用内部转发,则多个程序是同一个request作用域,如果参数想要传递,则可以利用request作用传递参数,但是重定向每次都是新的request对象,所以没有办法利用作用域传递参数。
由于内部转发是同一个请求,浏览器的URL不会发生变化,刷新浏览器时之前相关业务代码会重新执行一次,对服务器性能会造成一定额外压力,且易造成数据异常的问题。 但是重定向是浏览器进行二次请求,当前浏览器的URL地址会发生改变,如果刷新URL,之前的业务代码不会执行,只会执行与当前URL相关的代码。
下方上图 简单理解下: