Java Web(七)Request&Response

111 阅读5分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的17天,点击查看活动详情

Request&Response

image-20221015084537789

  • Request:获取请求数据
  • Response:设置响应数据

一.Request对象

1.Request继承体系

image-20221015095402692

  • Tomcat需要解析请求数据,封装为requestx对象并且创建requestx对象传递到service方法中
  • 使用request对象,查阅JavaEE API文档的HttpServletRequest接口

2.Request获取请求数据

2.1获取请求数据
  • 请求数据分为3部分:

    1.请求行:

    GET /request-demo/req1?username=zhangsan HTTP/1.1

    • String getMethod():获取请求方式:GET
    • String getContextPath():获取虚拟目录(项目访问路径):/request-demo
    • StringBuffer getRequestURL0:获取URL(统一资源定位符):http:/localhost:8080/request-demo/req1
    • String getRequestURI():获取URI(统一资源标识符):/request-demo/req1
    • String getQueryString() :获取请求参数(GET方式):username=zhangsan&password=123

    2.请求头

    User-Agent:Mozilla/5.0 Chrome/91.0.4472.106

    • String getHeader(String name):根据请求头名称,获取值

    3.请求体

    username=superbaby&password=123

    • ServletInputStream getlnputStream():获取字节输入流
    • BufferedReader getReader(():获取字符输入流
2.2通用方式获取请求参数
  • 请求参数获取方式

    get方式:

    String getQueryString()

    post方式:

    BufferedReader getReader()

思考:

GET请求方式和POST请求方式区别主要在于获取请求参数的方式不一样,是否可以提供一种统一获取请求参数的方式,从而统一doGet和doPost方法内的代码?

3.Request通用方式获取请求参数

image-20221015104523429

  • Map<String,String[]>getParameterMap():获取所有参数Map集合
  • String[]getParameterValues(String name):根据名称获取参教值(数组)
  • String getParameter(String name):根据名称获取参数值(单个值)
  • 使用通用方式获取请求参数后,屏蔽了GET和POST的请求方式代码的不同,则代码可以定义为如下格式:

    @WebServlet("/reqDemo3")
    public class RequestDemo3 extends HttpServlet{
        @override
        protected void doGet(HttpServletRequest req,HttpServletResponse resp){
    ​
        }
        @override
        protected void doPost(HttpServletRequest req,HttpServletResponse resp){
        this.doGet(req,resp);
        }
    }
    
  • 可以使用Servlet模板创建Servlet更高效

image-20221015111250096

若是没有new Servlet选项
  1. 在pom.xml文里导入servlet得依赖 image-20221015132441685
  2. 在File里的Project Structure找到Modules image-20221015132704638
  3. 点击Dependencies勾选servlet-api的选项 image-20221015132818874
  • 若想改变模板的格式

image-20221015133518929

4.Request请求参数中文乱码

  • 请求参数如果存在中文数据,则会乱码
//POST的乱码
//1.解决乱码:PoST的底层实现是getReader
request.setCharacterEncoding("UTF-8");//设置字符输入流的编码//要先设置编码格式,否则后续仍然会中文乱码//2.获取username
String username = request.getParameter("username");
System.out.println(username);
​
//GET的乱码
//1.GET,获取参数的方式:getQuerystring
//乱码原因:tomcat进行URL解码,默认的字符集IS0-8859-1
//1.1先对乱码数据进行编码:转为字节数组
username.getByte(StandardCharsets.IS0_8859_1);
//1.2字节数组解码
username = new String(bytes,StandardCharsets.ISO_8859_1)
//1.1和1.2可合为一行
username = new String(username.getBytes((StandardCharsets.ISO_8859_1),StandardCharsets.ISO_8859_1);
  • get的乱码原因

image-20221015135515956

  • URL编码

    1.将字符串按照编码方式转为二进制 2.每个字节转为2个16进制数并在前边加上%

    image-20221015135803178

  • 解决方案:

    POST:设置输入流的编码

    req.setCharacterEncoding("UTF-8");
    

    通用方式(GET/POST):先编码,再解码

    new String(username.getBytes("ISO-8859-1"),"UTF-8");

Tomcat8.0之后,已将GET请求乱码问题解决,设 置默认的解码方式为UTF-8

5.Request请求转发

  • 请求转发(forward):一种在服务器内部的资源跳转方式

image-20221015141804163

  • 实现方式
req.getRequestDispatcher(("资源B路径").forward(req,resp);
  • 请求转发资源间共享数据:使用Request对象

    • void setAttribute(String name,Object o):存储数据到request域中
    • Object getAttribute(String name):根据key,获取值
    • void removeAttribute(String name):根据key, 删除该键值对
  • 请求转发特点:

    浏览器地址栏路径不发生变化 只能转发到当前服务器的内部资源 一次请求,可以在转发的资源间使用request共享数据

二.Response对象

1.Response设置响应数据功能介绍

  • 响应数据分为3部分

    1.响应行:

    HTTP/1.1 200 OK

    • void setStatus(int sc):设置响应状态码

    2.响应头:

    Content-Type:text/html

    • void setHeader((String name,String value):设置响应头键值对

    3.响应体:

    head>
    • PrintWriter getWriter():获取字符输出流
    • ServletOutputStream getQutputStream():获取字节输出流

2.Response完成重定向

  • 重定向(Redirect):一种资源跳转方式

image-20221015143524237

  • 实现方式:
resp.setStatus(302);
resp.setHeader("location",“资源B的路径");
resp.sendRedirect("资源B的路径");
  • 重定向的特点

    浏览器地址栏路径发生变化 可以重定向到任意位置的资源(服务器内部、外部均可) 两次请求,不能在多个资源使用request共享数据

  • 路径问题

是否要加虚拟目录

明确路径谁使用? 浏览器使用:需要加虚拟目录(项目访问路径) 服务端使用:不需要加虚拟目录

//简化方式完成重定向
//动态获取虚拟目录
String contextPath = request.getContextPath();
response.sendRedirect(contextPath+"/resp2");

3.Response响应字符数据

  • 使用 1.通过Response对象获取字符输出流

    PrintWriter writer = resp.getWriter()
    

    2.写数据

    writer.write("aaa");
    

    正常写入数据就调用write方法即可,如想要写入html文本语言,则要设置ContentType

response.setContentType("text/html;charset=utf-8");
//1.获取字符输出流
PrintWriter writer response.getWriter();
//content-type
//response.setHeader("content-type","text/html");
writer.write(s:"你好");
writer.write(s:"<h1>aaa</h1>");
//细节:流不需要关闭
  • 注意 该流不需要关闭,随着响应结束,response对象销毁,由服务器关闭 中文数据乱码:原因通过Response获取的字符输出流默认编码:ISO-8859-1

    resp.setContentType("text/html;charset=utf-8");
    

4.Response响应字节数据

  • 使用 1.通过Responsel对象获取字符输出流

    ServletOutputStream outputStream = resp.getOutputStream();
    

    2.写数据

    outputStream,write(字节数据):
    
  • IOUtils工具类使用 1.导入坐标

    <dependency>
        <groupld>commons-io</groupld>
        <artifactld>commons-io</artifactld>
        <version>2.6</version>
    </dependency>
    

    2.使用

    IOUtils.copy(输入流,输出流);
    

5.SqlSession工具类抽取

  • 创建SqlSessionFactory代码优化

    //2.1获取SqlSessionFactory对象
    String resource "mybatis-config.xml";
    Inputstream inputstream = Resources.getResourceAsstream(resource);
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputstream);
    
  • 问题 1.代码重复:工具类 2.SqlSessionFactory工厂只创建一次,不要重复创建:静态代码块