Servlet response [httpServletResponse]


Preface:
The purpose of the doXXX method in the Servlet is to calculate the response according to the request, and then set the response data into the HttpServletResponse object; then Tomcat will convert the HttpServletResponse object into a string according to the format of the HTTP protocol, and pass the Socket write back to the browser

Summary of core methods

method describe
void setStatus(int sc) Set the status code for this response
void setHeader(String name,String value) Set a header with the given name and value, if name already exists, overwrite the old value
void addHeader(Stringname, String value) Add a header with the given name and value, if the name already exists, do not overwrite the old value, and add a new key-value pair in parallel
void setCharacterEncoding(Stringcharset) Sets the character encoding (MIME charset) of the response sent to the client, for example, UTF-8
void sendRedirect(String location) Sends a temporary redirect response to the client using the specified redirect location URL
void setContentType(Stringtype) Sets the content type of the response sent to the client
PrintWriter getWriter() Used to write text format data into the body
OutputStreamgetOutputStream() Used to write binary format data to the body

Notice:

  • The response object is the content that the server wants to return to the browser. The important information here is set by the programmer; therefore, the above methods
    are all "write" methods
  • The setting of the status code/response header should be placed before getWriter / getOutputStream, otherwise the setting may be invalid

code example

1.setStatus set status code

Front-end code:

<body>
    <h3>设置状态码</h3>
    <input type="text" id="status">
    </br>
    <button onclick="setStatus()">提交</button>
</body>

<script>
    function setStatus() {
    
    
        // js中发请求: 1)ajax; 2)直接修改url
        let status = document.querySelector("#status");
        // 后端会设置这个文本框输入的值为响应状态码: 严格来说 需要验证,此处省略
        window.location.href = "response?status=" + status.value;
    }
</script>

Backend code:

@WebServlet("/response")
public class ResponseServletStudy extends HttpServlet {
    
    
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
    
        // 获取请求发送的 queryString数据: status=xxx
        String status = req.getParameter("status");
        resp.setStatus(Integer.parseInt(status));
        resp.getWriter().write("设置响应状态码成功");
    }
}

After starting, open the page:
(garbled characters appear after submitting, don't care for now)

insert image description here

Use fiddler to capture packets:

insert image description here
Change the value of different status, you can see different response results

Note: If this method is not called, the status code 200 will be returned by default (if executed normally, there will be no exception; if an exception occurs, 500 will be returned)

2.setHeader set the response header [understand]

Modify the front-end code:

<body>
    <h3>设置状态码</h3>
    <input type="text" id="status">
    </br>
    <button onclick="setStatus()">提交</button>
    
    <h3>设置响应头</h3>
    <a href="response">设置</a>
</body>
<script>
    function setStatus() {
    
    
        // js中发请求: 1)ajax; 2)直接修改url
        let status = document.querySelector("#status");
        // 后端会设置这个文本框输入的值为响应状态码: 严格来说 需要验证,此处省略
        window.location.href = "response?status=" + status.value;
    }
</script>

Modify the backend code:

@WebServlet("/response")
public class ResponseServletStudy extends HttpServlet {
    
    
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
    
        // 获取请求发送的 queryString数据: status=xxx
        String status = req.getParameter("status");
        // 若请求数据包含需要设置的状态码,才执行
        if(status != null) {
    
    
            resp.setStatus(Integer.parseInt(status));
            resp.getWriter().write("设置响应状态码成功");
        }
        // 设置响应头的键值对,键可以是标准的Http响应头的键,也可以是自定义的
        // 响应状态码是301,302,307,响应头有Location字段,才是重定向
        resp.setHeader("Location","http://www.baidu.com");
        resp.setHeader("username","花花");
    }
}

Reboot, refresh the page:

insert image description here
After clicking, we found that we have set the location, but there is no jump. Use fiddler to capture the packet:
the status code is found to be 200

insert image description here
Note: If the response header name key already exists, the original key-value pair will be overwritten

3. addHeader set the response header [understand]

The only difference from setHeader is: the name key already exists, it will not affect adding a new one

4.setContentType

Set the value of the response header Content-Type, which is equivalent to setHeader("Content-Type", String type)
because Content-Type is the data format that identifies the body, so calling this method also needs to set the content of the body

  1. return a simple web page

Modify the front-end code:

<body>
    <h3>响应正文为简单的html网页</h3>
    <a href="html?type=1">查看</a>
</body>

Backend code:

@WebServlet("/html")
public class HtmlTypeServlet extends HttpServlet {
    
    
    // html?type=1...
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
    
        // 响应html: 设置响应的Content-Type
        resp.setContentType("text/html;charset=utf-8");

        PrintWriter pw = resp.getWriter();

        // 获取queryString中type的值
        String type = req.getParameter("type");
        // 返回简单的 html
        if("1".equals(type)) {
    
    
            pw.println("<h3>获取网页成功</h3>");
        }
    }
}

Restart, refresh the page, click to jump:

insert image description here

  1. Return a dynamic web page (complex html)

Front-end code:

<body> 
    <h3>响应正文为复杂的html(动态变化的)</h3>
    <input type="text" id="username" placeholder="输入用户名">
    </br>
    <button onclick="toWelcome()">跳转</button>
</body>

<script>
    function toWelcome() {
    
    
        let username = document.querySelector("#username");
        window.location.href = "html?type=2&username=" + username.value;
    }
</script>

Backend code:

@WebServlet("/html")
public class HtmlTypeServlet extends HttpServlet {
    
    
    // html?type=1...
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
    
        // 响应html: 设置响应的Content-Type
        resp.setContentType("text/html;charset=utf-8");

        PrintWriter pw = resp.getWriter();

        // 获取queryString中type的值
        String type = req.getParameter("type");
        // 返回简单的 html
        if("1".equals(type)) {
    
    
            pw.println("<h3>获取网页成功</h3>");
        }
        // 返回复杂的动态html
        else if("2".equals(type)) {
    
    
            // html>type=2&username=
            String username = req.getParameter("username");
            pw.println("<p>");
            pw.println("欢迎你!!" + username);
            pw.println("</p>");
        }
    }
}

Reboot, refresh the page:

insert image description here
Enter another username to try:

insert image description here
Regarding dynamic web pages, in Java code, a lot of html code is written, the coupling is too strong (two completely different programming languages ​​are developed together), and the maintainability and scalability are poor. Solutions: ①Template technology (
also exists For some problems, further development will lead to the emergence of ②ajax technology) (template technology will continue to be explained later)

Return to an existing web page

1. Redirection

Front-end code:

<body>
    <h3>重定向到hello.html</h3>
    <a href="goto?type=1">跳转</a>
    <h3>转发到hello.html</h3>
    <a href="goto?type=2">跳转</a>
</body>

Backend code:

@WebServlet("/goto")
public class GoToServlet extends HttpServlet {
    
    
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
    
        // goto?type=xxx
        String type = req.getParameter("type");
        // 重定向
        if("1".equals(type)) {
    
    
            resp.setStatus(301);
            resp.setHeader("Location","hello.html");
            // 以上代码可以简化为 sendRedirect
//            resp.sendRedirect("hello.html");
        }
        // 转发
        else if("2".equals(type)) {
    
    
            req.getRequestDispatcher("hello.html").forward(req,resp);
        }
    }
}

Restart the service and refresh the page:

insert image description here
Click on the redirected jump and use fiddler to capture the packet:

insert image description here

We can see the changes in the url address bar:

insert image description here
Features: ①The url address bar will change; ②Principle of sending two requests
:
the first time returns a 301 / 302 / 307 response status code, and the response header Location: the address of the web page; the
second time the browser automatically jumps to the address set by Location

2. Forward

The front and back end codes are the same as above

Click the forwarded jump and use fiddler to capture the packet:

insert image description here
Observe the url address bar:

insert image description here

Features: ①The url address column remains unchanged; ②There is only one request
Principle: When the Servlet is requested, the Servlet will obtain the resource of the forwarding path, and set the content of this path to the response body

return a file

Set the Content-Type and Content-Length, and then put the binary data of the file in the response body

Example 1. Rendering display

Take pictures and music files as an example

Front-end code:

<body>
    <h3>获取一个图片(渲染展示)</h3>
    <img src="file?type=photo&show=1">
    <h3>获取一个音乐(渲染展示)</h3>
    <audio src="file?type=music&show=1" controls></audio>
</body>

Backend code:

@WebServlet("/file")
public class FileServlet extends HttpServlet {
    
    
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
    

        // 获取响应对象的字节输出流
        OutputStream os = resp.getOutputStream();

        // 返回的文件类型: photo-图片 music-音乐
        String type = req.getParameter("type");
        // 返回时的操作: 1-渲染; 2-下载
        String show = req.getParameter("show");

        File file = null;
        // <img src="file?type=photo&show=1">
        if("photo".equals(type)) {
    
    
            resp.setContentType("image/jpeg"); //jpg格式
            file = new File("保存在 resources 里的完整路径");
        }
        // <audio src="file?type=music&show=1" controls></audio>
        else if("music".equals(type)) {
    
    
            resp.setContentType("audio/mp3"); // MP3格式
            file = new File("保存在 resources 里的完整路径,如: D:\\xxx\\xxx\\Servlet-Study\\src\\main\\resources\\love.mp3");
        }
        // 返回一个文件类型: Content-Length, body
        byte[] data = Files.readAllBytes(file.toPath());
        resp.setContentLength(data.length); // 等同于 setHeader("Content-Length",xxx)
        os.write(data);
    }
}

You can view the content-type comparison table in the rookie tutorial:

insert image description here

Start the service and open the page:
(here in gif format, no sound can be heard)

insert image description here

Example 2. Download

Modify the front-end code:

<body>
    <h3>获取一个图片(下载)</h3>
    <a href="file?type=photo&show=2">下载</a>
    <h3>获取一个音乐(下载)</h3>
    <a href="file?type=photo&show=2">下载</a>
</body>

Modify the backend code:

@WebServlet("/file")
public class FileServlet extends HttpServlet {
    
    
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
    

        // 获取响应对象的字节输出流
        OutputStream os = resp.getOutputStream();

        // 返回的文件类型: photo-图片 music-音乐
        String type = req.getParameter("type");
        // 返回时的操作: 1-渲染; 2-下载
        String show = req.getParameter("show");

        File file = null;
        // <img src="file?type=photo&show=1">
        if("photo".equals(type)) {
    
    
            if("1".equals(show)) {
    
    
                resp.setContentType("image/jpeg"); //jpg格式

            }
            else if("2".equals(show)) {
    
    
                resp.setContentType("application/octet-stream");
            }
            file = new File("D:\\Bite\\JAVA\\JavaCode\\Servlet-Study\\src\\main\\resources\\doge.jpg");
        }
        // <audio src="file?type=music&show=1" controls></audio>
        else if("music".equals(type)) {
    
    
            if("1".equals(show)) {
    
    
                resp.setContentType("audio/mp3"); // MP3格式
            }
            else if("2".equals(show)) {
    
    
                resp.setContentType("application/octet-stream");
            }
            file = new File("D:\\Bite\\JAVA\\JavaCode\\Servlet-Study\\src\\main\\resources\\love.mp3");
        }
        // 返回一个文件类型: Content-Length, body
        byte[] data = Files.readAllBytes(file.toPath());
        resp.setContentLength(data.length); // 等同于 setHeader("Content-Length",xxx)
        os.write(data);
    }
}

Reboot, refresh the page:

insert image description here

open a file:

insert image description here
Modify the file extension:

insert image description here

Thinking: Pictures, music, and videos are static files. They can be directly accessed by placing them directly under the webapp. Do you need a Servlet to return them? Is this superfluous?
.If
the total size of the file is very large, it is not suitable to put it under the webapp of the web application (it will be more laborious to pack it later), and it is more appropriate to use Servlet to read the file from other local places and return it.

return json data

Commonly used in ajax requests to return some data; used to dynamically populate web pages

Backend code:

@WebServlet("/ajax-response")
public class AjaxJsonServlet extends HttpServlet {
    
    
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
    
        List<Message> messages = new ArrayList<>();
        Message m1 = new Message("杰杰子","花花","你一定能找到好工作的!");
        Message m2 = new Message("花花","杰杰子","我一定可以的!");
        messages.add(m1);
        messages.add(m2);
        ObjectMapper mapper = new ObjectMapper();
        // 把 java对象转换为 json字符串; List和数组会转换为[],一个对象{成员变量名: 值}
        String json = mapper.writeValueAsString(messages);
        System.out.println("转化的json字符串:" + json);

        // 设置json, 可以不设置 Content-Length, tomcat会设置
        resp.setContentType("application/json; charset=utf-8");
        resp.getWriter().println(json);
    }
    static class Message {
    
    
        private String from; //谁
        private String to;   //对谁
        private String info; //说了什么

        public Message(String from, String to, String info) {
    
    
            this.from = from;
            this.to = to;
            this.info = info;
        }

        public String getFrom() {
    
    
            return from;
        }

        public void setFrom(String from) {
    
    
            this.from = from;
        }

        public String getTo() {
    
    
            return to;
        }

        public void setTo(String to) {
    
    
            this.to = to;
        }

        public String getInfo() {
    
    
            return info;
        }

        public void setInfo(String info) {
    
    
            this.info = info;
        }
    }
}

Start the service, open the web page, and view:
insert image description here
backend output:

insert image description here
Add the front-end code:

<body>
    <h3>获取ajax响应数据,动态生成网页内容</h3>
    <button onclick="generate()">试试丫</button>
    <div id="content"></div>
</body>

<script>
    function generate() {
    
    
        let content = document.querySelector("#content");
        ajax({
    
    
            url: "ajax-response",
            method: "get",
            callback: function(status,resp){
    
    
                console.log(resp);
                // resp 是一个字符串
                //转换为 json对象
                let array = JSON.parse(resp);
                // 遍历
                for(json of array) {
    
    
                    // 每个json对象,创建一个dom来保存信息
                    let p = document.createElement("p");
                    p.innerHTML = json.from + "对" + json.to + "说" + json.info;
                    content.appendChild(p);
                }
            }
        });
    }
    function ajax(args){
    
    //var ajax = function(){}
        let xhr = new XMLHttpRequest();
        // 设置回调函数
        xhr.onreadystatechange = function(){
    
    
            // 4: 客户端接收到响应后回调
            if(xhr.readyState == 4){
    
    
                // 回调函数可能需要使用响应的内容,作为传入参数
                args.callback(xhr.status, xhr.responseText);
            }
        }
        xhr.open(args.method, args.url);
        //如果args中,contentType属性有内容,就设置Content-Type请求头
        if(args.contentType){
    
    //js中,if判断,除了判断boolean值,还可以判断字符串,对象等,有值就为true
            xhr.setRequestHeader("Content-Type", args.contentType);
        }
        //如果args中,设置了body请求正文,调用send(body)
        if(args.body){
    
    
            xhr.send(args.body);
        }else{
    
    //如果没有设置,调用send()
            xhr.send();
        }
    }
</script>

refresh page:

insert image description here

Process analysis:

insert image description here
The client initiates an Http request:

Several request data correspond to available data formats:

Data Format queryString form from-data json
js: window.location.href = " "
html: <a href=" " / <img src=" " / …
Enter the url directly in the browser address bar
< form> form tag √ (post) √ (post,form-data)
js: ajax

Server-side processing:

  1. HttpServletRequest gets request data:
method of obtaining queryString form from-data json
getParameter Simple types can get
getPart √ (uploaded file)
getInputStream (can get request body data in any format) × (It is more complicated to analyze by yourself, generally not used) ×

Notice: The keys in the json string need to be consistent with the member variable names in the custom type(Generally parsed as a custom type)

  1. Verify according to the requested data, business logic processing (such as database operations)

Verification : For example, the format of the account phone number
Business logic processing : According to a certain field of the request data, execute different logic, such as type=1 to return to the login page; type=0 to return to the home page, and may also perform database operations, etc.

  1. Return the content of the response
    and return the http response to the client
  • Web page: generally use the template technology to return the web page instead of splicing dynamic html in Servlet
  • ②File : as needed
  • json: the first part is the ajax request sent, which is more common

The client handles the Http response:

  • Web page: rendering (automatically executed by the browser)
  • ②File : rendering or downloading (automatically executed by the browser)
  • json: JavaScript writes ajax code to complete
    the front-end code:
    parse the response body (json string) into a json object: JSON.parse(body);
    use JavaScript DOM api to generate some DOM elements, and convert the fields in the json object set into DOM elements (attributes, tag content...)

insert image description here

Guess you like

Origin blog.csdn.net/m0_47988201/article/details/123322630