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)
Use fiddler to capture packets:
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:
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
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
- 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:
- 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:
Enter another username to try:
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:
Click on the redirected jump and use fiddler to capture the packet:
We can see the changes in the url address bar:
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:
Observe the url address bar:
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:
Start the service and open the page:
(here in gif format, no sound can be heard)
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:
open a file:
Modify the file extension:
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:
backend output:
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:
Process analysis:
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:
- 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)
- 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.
- 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...)