Request
Servlet请求对应的是ServletRequest对象,它有一个子类HttpServletRequet基于Http协议的规则对请求数据进行了封装。我们可以使用HttpServletRequet对象的方法来获取请求数据,来完成功能的开发。
1.获取各种路径的方法
public String getContextPath()
获取虚拟名称
public String getServletPath()
获取servlet映射路径
public String getRemoteAddr()
获取远程访问者ip地址
public String getQueryString()
获取请求消息数据
public String getRequestURI()
获取统一资源标识符(虚拟目录+访问地址)
public String getRequestURL()
获取统一资源定位符(完整路径)
@WebServlet("/servletRequestDemo1")
public class ServletRequestDemo1 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//获取虚拟目录
String contextPath = req.getContextPath();
System.out.println("虚拟目录:"+contextPath);
//获取Servlet映射路径
String servletPath = req.getServletPath();
System.out.println("servlet访问路径:"+servletPath);
//获取访问者ip地址:
String remoteAddr = req.getRemoteAddr();
System.out.println("访问者ip:"+remoteAddr);
//获取统一资源标识符(虚拟目录+访问地址)
String requestURI = req.getRequestURI();
System.out.println("资源标识符:"+requestURI);
//获取统一资源定位符(完整路径)
StringBuffer requestURL = req.getRequestURL();
System.out.println("统一资源定位符:"+requestURL);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
2.获取请求头信息的方法
请求头是浏览器告诉服务器的一些请求配置信息,以键值对的形式存在。
public String getHeader(String name)
根据请求头名称获取一个值
public Enumeration<String> getHeaders(String name)
根据请求头名称获取多个值
public Enumeration<String> getHeaderNames()
获取所有请求头名称
@WebServlet("/servletRequestDemo2")
public class ServletRequestDemo2 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//获取一个请求头
String connection = req.getHeader("connection");
System.out.println(connection);
System.out.println("----------------");
//获取一个请求头的多个值
Enumeration<String> values = req.getHeaders("accept-encoding");
while (values.hasMoreElements()) {
String value = values.nextElement();
System.out.println(value);
}
System.out.println("------------");
//获取所有的请求头名称
Enumeration<String> headerNames = req.getHeaderNames();
//遍历请求头名称,根据名称获取值
while (headerNames.hasMoreElements()) {
String headName = headerNames.nextElement();
String headValue = req.getHeader(headName);
System.out.println(headName+"="+headValue);
}
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
3.获取请求参数信息的方法
public String getParameter(String name)
根据名称获取数据
public String[] getParameterValues(String name)
根据名称获取所有数据
public Enumeration<String> getParameterNames()
获取所有名称
public Map<String,String[]> getParameterMap()
获取所有参数的键值对
创建一个regist.html页面(参考源代码),然后使用Servlet获取参数信息
@WebServlet("/servletRequestDemo3")
public class ServletRequestDemo3 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//根据参数名获取参数指
String username = req.getParameter("username");
System.out.println("姓名:"+username);
//根据参数名获取多个值
String[] hobbies = req.getParameterValues("hobby");
System.out.println("爱好:"+ Arrays.toString(hobbies));
System.out.println("---------");
//获取所有的参数名称
Enumeration<String> parameterNames = req.getParameterNames();
while (parameterNames.hasMoreElements()) {
String parameterName = parameterNames.nextElement();
String[] values = req.getParameterValues(parameterName);
System.out.println(parameterName+":"+Arrays.toString(values));
}
System.out.println("----------");
//获取所有的参数名和参数值,存入一个Map集合
Map<String, String[]> parameterMap = req.getParameterMap();
Set<String> keys = parameterMap.keySet();
for (String key : keys) {
String[] values = parameterMap.get(key);
System.out.println(key+"="+Arrays.toString(values));
}
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
4.获取参数封装对象
需要用到beanutils工具类,把jar包复制到web/WEB-INF/libs目录下
1.手动封装方式
获取所有的对象,把对象封装在我们新建的实体类中
2.反射封装的方式
3.工具类封装方式
@WebServlet("/servletRequestDemo5")
public class ServletRequestDemo5 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//获取所有的参数名和参数指,存入一个Map集合
Map<String, String[]> parameterMap = req.getParameterMap();
Student stu=new Student();
try {
BeanUtils.populate(stu,parameterMap);
System.out.println(stu);
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
5.流对象获取数据
public BufferedReader getReader()
获取字符输入流(提交方式必须是post)
public ServletInputStream getInputStream()
获取字节输入流
6.请求数据乱码问题
GET方式
没有乱码问题
POST方式
有乱码问题,可以通过setCharacterEncoding()方法来解决
//设置请求字符编码
req.setCharacterEncoding("UTF-8");
7.请求域
1.请求域(request域):可以在一次请求范围内进行共享数据
2.一般用于请求转发的多个资源中的共享数据
3.请求对象操作共享数据方法
设置数据、获取数据、移除数据
- 在Servlet7中设置共享数据
@WebServlet("/servletRequestDemo7")
public class ServletRequestDemo7 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//设置请求编码
req.setCharacterEncoding("utf-8");
//设置请求参数
req.setAttribute("user","李四");
req.getRequestDispatcher("/servletRequestDemo8").forward(req,resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
- 在Servlet8中获取共享数据
@WebServlet("/servletRequestDemo8")
public class ServletRequestDemo8 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//设置请求编码
req.setCharacterEncoding("utf-8");
//获取请求共享数据
Object user = req.getAttribute("user");
System.out.println(user);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
8.请求转发
1.请求转发:客户端的一次请求到达后,发现需要借助其他Servlet来实现功能
2.特点:
浏览器地址栏不变
域对象的数据不丢失
负责转发的Servlet转发前后的响应正文会丢失
由转发的目的地来响应客户端
public RequestDispatcher getRequestDispatcher(String name)
获取请求调度对象
public void forward(HttpServletRequest req, HttpServletResponse resp)
实现转发
Response
浏览器访问服务器后,服务器给客户端响应的数据会封装为ServletResponse对象,它有一个子类叫HttpServletResponse对象,用于封装按照Http协议封装的响应数据。
1.常见状态码
状态码 | 状态 |
---|---|
100 | 只有请求的一部分已经被服务器接收,但只要它没有被拒绝,客户端应继续该请求 |
200 | 请求成功 |
302 | 重定向,所请求的页面已经临时转移到一个新的 URL |
304 | 访问缓存,所请求的页面已经临时转移到一个新的 URL |
404 | 客户端错误,请求路径服务器没有对应的资源 |
405 | 客户端错误,请求方式找不到对应的方法 |
500 | 服务端错误,可能服务器内部有异常 |
2.响应数据乱码解决
字节流:
public ServletOutputStream getOutputStream()
获取响应字节输出流对象
字符流:
public PrintWriter getWriter()
获取响应字符输出流对象
解决乱码问题
public void setContentType("text/html;charset=UTF-8")
设置响应内容类型,解决中文乱码问题
//设置响应编码
resp.setContentType("text/html;charset=utf-8");
- 使用字符流响应数据
@WebServlet("/servletResponseDemo1")
public class ServletResponseDemo1 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//设置响应编码
resp.setContentType("text/html;charset=utf-8");
//输出响应数据
resp.getWriter().println("<h1>你好,这是一个响应消息</h1>");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
- 使用字节流响应数据
@WebServlet("/servletResponseDemo2")
public class ServletResponseDemo2 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//设置响应编码
resp.setContentType("text/html;charset=utf-8");
//输出响应数据
ServletOutputStream outputStream = resp.getOutputStream();
outputStream.write("你好世界".getBytes("utf-8"));
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
3.响应图片
在web/img目录下放一张a.jpeg图片,把图片中所有的字节响应给客户端。
读取文件的时候注意图片的绝对路径(web目录是根目录)
String realPath = getServletContext().getRealPath("/img/autumn.jpg");
@WebServlet("/servletResponseDemo3")
public class ServletResponseDemo3 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//获取输出流对象
ServletOutputStream out = resp.getOutputStream();
//获取文件的绝对路径
String imgPath = getServletContext().getRealPath("img/a.jpeg");
//获取输入流对象
FileInputStream fis = new FileInputStream(imgPath);
byte[] bs=new byte[1024];
int len;
while ((len=fis.read(bs))!=-1){
out.write(bs,0,len);
}
fis.close();
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
4.设置缓存
缓存:对于不经常变化的数据,我们可以设置合理的缓存时间,以避免浏览器频繁请求服务器,以此提高效率
public void setDateHeader(String name,long time)
设置消息头添加缓存
resp.setDateHeader("Expires",System.currentTimeMillis()+1*60*60*1000);
5.定时刷新
定时刷新:过了指定时间后,页面自动进行跳转
public void setHeader(String name,String value)
设置消息头的定时刷新
resp.setHeader("Refresh","3;URL=/response/login.html");
@WebServlet("/servletDemo05")
public class ServletDemo05 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//1.设置编码
resp.setContentType("text/html;charset=UTF-8");
//2.写数据
PrintWriter pw = resp.getWriter();
pw.write("定时刷新,3秒后跳转");
//定时跳转
resp.setHeader("Refresh","3;URL=/response/login.html");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req,resp);
}
}
6.重定向
1.重定向:客户端的一次请求到达后,发现需要借助其他servlet来实现功能
2.特点:浏览器地址栏会发生改变,俩次请求,请求域对象不能共享数据,可以重定向到其他服务器
3.原理:
设置响应状态码为302 (resp.setStatus(302))
设置响应的资料路径(响应到到了去,通过响应消息头location来指定)
public void sendRedirect(String name)
设置重定向
resp.sendRedirect(req.getContextPath()+"/servletDemo07");
@WebServlet("/servletResponseDemo6")
public class ServletResponseDemo6 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html;charset=utf-8");
//重定向到servletResponseDemo5
//resp.sendRedirect(req.getContextPath()+"/servletResponseDemo5");
//也可以使用下面两个方法,完成重定向;302表示重定向的状态码
resp.setStatus(302);
resp.setHeader("location",req.getContextPath()+"/servletResponseDemo5");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
7.文件下载
写一个html页面,点击图片开始下载
<a href="/day03_Servlet/servletResponseDemo7">点击下载图片</a>
写以Servlet处理下载的请求,给客户端响应一张图片
@WebServlet("/servletResponseDemo7")
public class ServletResponseDemo7 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//准备要下载的图片
File file=new File("img/a.jpeg");
//设置响应头,告诉浏览器以附件形式接受
resp.setHeader("content-disposition","attachment;filename="+file.getName());
//获取输出流对象
ServletOutputStream out = resp.getOutputStream();
//获取文件的绝对路径
String imgPath = getServletContext().getRealPath(file.getPath());
//获取输入流对象
FileInputStream fis = new FileInputStream(imgPath);
byte[] bs=new byte[1024];
int len;
while ((len=fis.read(bs))!=-1){
out.write(bs,0,len);
}
fis.close();
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
8.路径问题
* 路径写法:
1. 路径分类
1. 相对路径:通过相对路径不可以确定唯一资源
* 如:./index.html
* 不以/开头,以.开头路径
* 规则:找到当前资源和目标资源之间的相对位置关系
* ./:当前目录
* ../:后退一级目录
2. 绝对路径:通过绝对路径可以确定唯一资源
* 如:http://localhost/day15/responseDemo2 /day15/responseDemo2
* 以/开头的路径
* 规则:判断定义的路径是给谁用的?判断请求将来从哪儿发出
* 给客户端浏览器使用:需要加虚拟目录(项目的访问路径)
* 建议虚拟目录动态获取:request.getContextPath()
* <a> , <form> 重定向...
* 给服务器使用:不需要加虚拟目录
* 转发路径