09_Java Web——Request&Response


Request&Response

Request:获取请求数据
Response:设置响应数据
//初识Request&Response
@WebServlet("/demo3")
public class ServletDemo3 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //使用request对象,获取请求数据
        String name = req.getParameter("name");
        //使用response对象,设置响应数据
        resp.setHeader("Content-Type", "text/html;charset=utf-8");
        resp.getWriter().write("<h1>Hello " + name + "</h1>");
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("doPost");
    }
}

Request对象

Request继承体系

ServletRequest:Java提供的请求对象根接口
HttpServletRequest:Java提供的对HTTP协议封装的请求对象接口
RequestFacade:Tomcat定义的实现类
  1. Tomcat需要解析请求数据,封装为request对象,并且创建request对象传递到service方法中
  2. 使用request对象,查阅JavaEE API文档的HttpServletRequest接口即可

Request获取请求数据

获取请求数据

1. 请求行

String getMethod()  //获取请求方式
String getContextPath() //获取虚拟目录(项目访问路径)
StringBuffer getRequestURL()    //获取URL(统一资源定位符)
String getRequestURI()  //获取URI(统一资源标识符)
String getQueryString() //获取请求参数(GET方式)
@WebServlet("/req1")
public class RequestDemo extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//        String getMethod()  //获取请求方式
        String method = req.getMethod();
        System.out.println("请求方式:" + method);
//        String getContextPath() //获取虚拟目录(项目访问路径)
        String contextPath = req.getContextPath();
        System.out.println("虚拟目录:" + contextPath);
//        StringBuffer getRequestURL()    //获取URL(统一资源定位符)
        StringBuffer requestURL = req.getRequestURL();
        System.out.println("URL:" + requestURL.toString());
//        String getRequestURI()  //获取URI(统一资源标识符)
        String requestURI = req.getRequestURI();
        System.out.println("URI:" + requestURI);
//        String getQueryString() //获取请求参数(GET方式)
        String queryString = req.getQueryString();
        System.out.println("请求参数:" + queryString);
    }
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    }
}

2. 请求头

String getHeader(String name)   //根据请求头名称获取值
@WebServlet("/req1")
public class RequestDemo extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//        String getHeader(String name)   //根据请求头名称获取值
        String header = req.getHeader("User-Agent");
        System.out.println(header);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    }
}

3. 请求体
只有post请求才有请求体

ServletInputStream getInputStream() //获取字节输入流
BufferedReader getReader()  //获取字符输入流
@WebServlet("/req1")
public class RequestDemo extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    }
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //获取post请求体:请求参数
        //1. 获取字符输入流
        BufferedReader reader = req.getReader();
        //2. 读取数据
        String line = reader.readLine();
        System.out.println(line);
    }
}

通用方式获取请求数据

GET方式:String getQueryString()
Post方式:BufferedReader getReader()
Map<String, String[]> getParameterMap() //获取所有参数Map集合
String[] getParameterValues(String name)    //根据名称获取参数值(数组)
String getParameter(String name)    //根据名称获取参数值(单个值)
@WebServlet("/req1")
public class RequestDemo extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //get请求逻辑
        //System.out.println("get...");
        //1. 获取所有参数的Map集合
        Map<String, String[]> map = req.getParameterMap();
        for (String key : map.keySet()) {
            System.out.print(key + ":");
            String[] values = map.get(key);
            for (String value : values) {
                System.out.print(value + " ");
            }
            System.out.println();
        }
        //2. 根据key获取参数值(数组)
        String[] hobbies = req.getParameterValues("hobby");
        for (String hobby : hobbies) {
            System.out.println(hobby);
        }
        //3. 根据key获取参数值(单个)
        String username = req.getParameter("username");
        String password = req.getParameter("password");
        System.out.println(username + ":" + password);
    }
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //post请求逻辑
        //System.out.println("post...");
        this.doGet(req, resp);
    }
}

请求参数中文乱码处理

解决方案:
    post:
        原因:getReader()获取字符输入流,Tomcat默认获取流的编码为ISO-8859-1
        解决:设置输入流的编码  req.setCharacterEncoding("UTF-8");
    get:
        原因:浏览器将中文进行UTF-8格式URL编码,Tomcat再进行URL解码
             而Tomcat默认解码格式为ISO-8859-1
        解决:1. 先对乱码数据进行编码,转为字节数组
             2. 将字节数组转为字符串
    注:Tomcat8.0版本之后,已将GET请求乱码问题解决,设置默认编码方式为UTF-8

URL编码:

  1. 将字符串按照编码方式转为二进制
  2. 每个字节转为2个16进制数并在前边加上%
//模拟get方式编码解码
public class URLDemo {
    public static void main(String[] args) throws UnsupportedEncodingException {
        String name = "张三";
        //1. 模拟浏览器编码
        String encode = URLEncoder.encode(name, "utf-8");
        System.out.println(encode);
        //2. 模拟Tomcat解码
        String decode = URLDecoder.decode(encode, "ISO-8859-1");
        System.out.println(decode);

        //解决中文乱码
        //3. 转为字节数据
        byte[] bytes = decode.getBytes("ISO-8859-1");
        for (byte b : bytes) {
            System.out.print(b + " ");
        }
        //4. 将字节数组转为字符串
        String s = new String(bytes, "UTF-8");
        System.out.println(s);
    }
}
@WebServlet("/req1")
public class RequestDemo extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //1. 解决乱码:Post方式
        req.setCharacterEncoding("UTF-8");

        //测试中文乱码
        String username = req.getParameter("username");
        System.out.println(username);

        //解决乱码:Get方式与Post方式通用
        //3.1 先对乱码数据进行编码,转为字节数组
        byte[] bytes = username.getBytes("ISO-8859-1");
        //3.2 再对字节数组进行解码,转为字符串
        username = new String(bytes, "UTF-8");
        System.out.println(username);
    }
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        this.doGet(req, resp);
    }
}

Request请求转发

请求转发(forward):一种在服务器内部的资源跳转方式
实现方式:  req.getRequestDispatcher("资源路径").forward(req, resp);

请求转发资源间共享数据:使用Request对象
  1. void setAttribute(String name, Object o):设置数据到request域中
  2. Object getAttribute(String name):根据key获取值
  3. void removeAttribute(String name):根据key删除该键值对
//ForwardDemoA.java
@WebServlet("/fdA")
public class ForwardDemoA extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("ForwardDemoA");
        //存储数据
        req.setAttribute("name", "tom");
        //请求转发
        req.getRequestDispatcher("/fdB").forward(req, resp);
    }
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        this.doGet(req, resp);
    }
}
//ForwardDemoB.java
@WebServlet("/fdB")
public class ForwardDemoB extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("ForwardDemoB");
        //获取数据
        Object name = req.getAttribute("name");
        System.out.println("name:" + name);
    }
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        this.doGet(req, resp);
    }
}

请求转发的特点

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

Response对象

Response继承体系

ServletResponse:Java提供的请求对象根接口
HttpServletResponse:Java提供的对HTTP协议封装的请求对象
ResponseFacade:Tomcat定义的实现类

Response设置响应数据功能介绍

1. 响应行

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

2. 响应头

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

3. 响应体

PrintWriter getWriter() //获取字符输出流
ServletOutputStream getOutputStream()   //获取字节输出流

Response完成重定向

重定向(Redirect):一种资源跳转方式
实现方法:
    resp.setStatus(302);
    resp.setHeader("location", "资源路径");
//RedirectDemoA.java
@WebServlet("/RDA")
public class RedirectDemoA extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("RedirectDemoA");
        //重定向
        //1. 设置响应状态码
//        resp.setStatus(302);
        //2. 设置响应头
//        resp.setHeader("Location", "/RDB");

        //简化方式实现重定向
        resp.sendRedirect("/RDB");
    }
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        this.doGet(req, resp);
    }
}
//RedirectDemoB.java
@WebServlet("/RDB")
public class RedirectDemoB extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("RedirectDemoB");
    }
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        this.doGet(req, resp);
    }
}

重定向特点

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

路径问题

明确路径由谁使用:
    浏览器使用:需要加虚拟目录
    服务端使用:不需要加虚拟目录
@WebServlet("/RDA")
public class RedirectDemoA extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("RedirectDemoA");
        //重定向
        //动态获取虚拟目录
        String contextPath = req.getContextPath();
        //简化方式实现重定向
        resp.sendRedirect(contextPath + "/RDB");
    }
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        this.doGet(req, resp);
    }
}

Response响应字符数据

使用:
    1. 通过Response对象获取字符输出流
        PrintWriter writer = resp.getWriter();
    2. 写数据
        writer.write("aaa");
@WebServlet("/resp")
public class ResponseDemo extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //设置
        resp.setContentType("text/html;charset=utf-8");
        //1. 获取字符输出流
        PrintWriter writer = resp.getWriter();
        //resp.setHeader("Content-Type", "text/html;charset=utf-8");
        //2. 写数据
        writer.write("hello world");
        writer.write("<h1>hello world</h1>");
    }
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        this.doGet(req, resp);
    }
}
注意:
    该流无需关闭,随着响应结束,response对象销毁,由服务器关闭
    中文数据乱码原因:通过Response获取的字符输出流默认编码为ISO-8859-1

Response响应字节数据

使用:
    1. 通过Response对象获取字节输出流
        ServletOutputStream outputStream = resp.getOutputStream();
    2. 写数据
        outputStream.write(字节数据);
@WebServlet("/resp")
public class ResponseDemo extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //1. 读取文件
        FileInputStream fileInputStream = new FileInputStream("C://a.png");
        //2. 获取字节输出流
        ServletOutputStream outputStream = resp.getOutputStream();
        //3. 完成流的copy
//        byte[] bytes = new byte[1024];
//        int len = 0;
//        while ((len = fileInputStream.read(bytes)) != -1) {
//            outputStream.write(bytes, 0, len);
//        }
        //使用IOUtils完成流的copy(需要在pom.xml中导入commons-io坐标)
        IOUtils.copy(fileInputStream, outputStream);
        //4. 关闭流
        fileInputStream.close();
    }
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        this.doGet(req, resp);
    }
}

案例

环境准备:

  1. 创建web项目(详情查看Web笔记
  2. 在webapp目录下创建静态页面资源
  3. 创建数据库和对应的user表
  4. 导入MyBatis坐标,Mysql驱动坐标(详情查看MyBatis笔记
  5. 创建mybatis-config.xml核心配置文件,UserMapper.xml映射文件,UserMapper接口(详情查看MyBatis笔记

用户登录

流程:
    1. 用户填写用户名和密码,提交到LoginServlet
    2. 在LoginServlet中使用MyBatis查询数据库,返回User对象,验证用户名密码是否正确
    3. 如果User对象不为null,则账号密码正确,响应登录成功,反之错误,响应登录失败
@WebServlet("/loginServlet")
public class LoginServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //1. 接收用户名和密码
        String username = req.getParameter("username");
        String password = req.getParameter("password");

        //2. 调用MyBatis完成查询
        //2.1 获取sqlSessionFactory对象
        String resource = "mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream (resource);
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        //2.2 获取sqlSession对象
        SqlSession sqlSession = sqlSessionFactory.openSession();
        //2.3 获取Mapper
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        //2.4 调用方法
        User user = mapper.select(username, password);
        //2.5 关闭资源
        sqlSession.close();

        //获取字符输出流,并设置编码格式
        resp.setContentType("text/html;charset=utf-8");
        PrintWriter writer = resp.getWriter();
        //3. 判断结果
        if (user != null) {
            //登录成功
            writer.write("<h1>登录成功</h1>");
        }else{
            //登录失败
            writer.write("<h1>登录失败</h1>");
        }
    }
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        this.doGet(req, resp);
    }
}

用户注册

流程:
    1. 用户填写用户名、密码等信息,点击注册按钮,提交到RegisterServlet
    2. 在RegisterServlet中使用MyBatis保存数据
    3. 保存前,需要判断用户名是否已经存在:根据用户名查询数据库
@WebServlet("/registerServlet")
public class RegisterServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //1. 接收用户数据
        String username = req.getParameter("username");
        String password = req.getParameter("password");
        //封装用户对象
        User user = new User();
        user.setUsername(username);
        user.setPassword(password);
        //2. 调用mapper,根据用户名查询用户对象
        //2.1 获取sqlSessionFactory对象
        String resource = "mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream (resource);
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        //2.2 获取sqlSession对象
        SqlSession sqlSession = sqlSessionFactory.openSession();
        //2.3 获取Mapper
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        //2.4 调用方法
        User user1 = mapper.selectByUsername(username);
        //3. 判断用户是否存在
        if (user1 == null) {
            //4. 如果不存在,调用mapper,插入用户
            mapper.add(user);
            //提交事务
            sqlSession.commit();
            sqlSession.close();
        }else{
            //5. 如果存在,提示用户已经存在
            resp.setContentType("text/html;charset=utf-8");
            resp.getWriter().write("用户已经存在");
        }
    }
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        this.doGet(req, resp);
    }
}

代码优化

在创建SqlSessionFactory代码中有以下问题:
    1. 代码重复
    2. SqlSessionFactory工厂只创建一次,不要重复创建
解决方法:
    1. 工具类
    2. 静态代码块
public class SqlSessionFactoryUtils {
    private static SqlSessionFactory sqlSessionFactory;
    static {
        //静态代码块随着类的加载而自动执行,并且只执行一次
        try {
            String resource = "mybatis-config.xml";
            InputStream inputStream = Resources.getResourceAsStream (resource);
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    public static SqlSessionFactory getSqlSessionFactory() {
        return sqlSessionFactory;
    }
}
//2.1 获取sqlSessionFactory对象
SqlSessionFactory sqlSessionFactory = SqlSessionFactoryUtils.getSqlSessionFactory();
sqlSession对象不能够让所有用户共享
因为sqlSession代表用户和数据库的连接
不能够让所有用户共享一个连接

附:案例资源

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
文件上传是Web开发中常见的功能之一,Java中也提供了多种方式来实现文件上传。其中,一种常用的方式是通过Apache的commons-fileupload组件来实现文件上传。 以下是实现文件上传的步骤: 1.在pom.xml文件中添加以下依赖: ```xml <dependency> <groupId>commons-fileupload</groupId> <artifactId>commons-fileupload</artifactId> <version>1.3.3</version> </dependency> ``` 2.在前端页面中添加文件上传表单: ```html <form method="post" enctype="multipart/form-data" action="upload"> <input type="file" name="file"> <input type="submit" value="Upload"> </form> ``` 3.在后台Java代码中处理上传文件: ```java // 创建一个DiskFileItemFactory对象,用于解析上传的文件 DiskFileItemFactory factory = new DiskFileItemFactory(); // 设置缓冲区大小,如果上传的文件大于缓冲区大小,则先将文件保存到临时文件中,再进行处理 factory.setSizeThreshold(1024 * 1024); // 创建一个ServletFileUpload对象,用于解析上传的文件 ServletFileUpload upload = new ServletFileUpload(factory); // 设置上传文件的大小限制,这里设置为10MB upload.setFileSizeMax(10 * 1024 * 1024); // 解析上传的文件,得到一个FileItem的List集合 List<FileItem> items = upload.parseRequest(request); // 遍历FileItem的List集合,处理上传的文件 for (FileItem item : items) { // 判断当前FileItem是否为上传的文件 if (!item.isFormField()) { // 获取上传文件的文件名 String fileName = item.getName(); // 创建一个File对象,用于保存上传的文件 File file = new File("D:/uploads/" + fileName); // 将上传的文件保存到指定的目录中 item.write(file); } } ``` 以上代码中,首先创建了一个DiskFileItemFactory对象,用于解析上传的文件。然后设置了缓冲区大小和上传文件的大小限制。接着创建一个ServletFileUpload对象,用于解析上传的文件。最后遍历FileItem的List集合,判断当前FileItem是否为上传的文件,如果是,则获取文件名,创建一个File对象,将上传的文件保存到指定的目录中。 4.文件上传完成后,可以给用户一个提示信息,例如: ```java response.getWriter().write("File uploaded successfully!"); ``` 以上就是使用Apache的commons-fileupload组件实现文件上传的步骤。需要注意的是,文件上传可能会带来安全隐患,因此在处理上传的文件时,需要进行严格的校验和过滤。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

子平Zziping

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值