在实际使用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相关的代码。