一)RESTful简介
定义:RESTful是一种网络应用程序的设计风格和开发方式,基于HTTP,可以使用XML格式定义或JSON格式定义。
RESTful特点:
1、每一个URI都是一个唯一资源标识符;
2、客户端使用GET、POST、PUT、DELETE4个表示操作方式的动词对服务端资源进行操作:GET用来获取资源,POST用来新建资源(也可以用于更新资源),PUT用来更新资源,DELETE用来删除资源;
3、资源的表现形式是XML或HTML或JSON;
4、客户端与服务端之间的交互在请求之间都是无状态的;
二)SpringMVC对RESTful的支持
主要是通过注解来实现功能,如下:
@Controller:声明一个处理请求的控制器
@RequestMapping:请求映射地址到对应的方法,该注解又可以分为一下几种类型:
@GetMapping:获取资源。
@PostMpping:新建资源(也可以用于更新资源)。
@PutMapping:更新资源,主要是用来更新整个资源的。
@DeleteMapping:删除资源。
@PatchMapping:更新资源,主要是用来执行某项操作并更新资源的某些字段。
@ResponsrBody:将响应内容转换为JSON格式。
@RequestBody:请求内容转换为JSON格式。
@RestContrller:等同于@Controller+@ResponsrBody注解。
三)RESTful API统一返回值
第一步:创建一个枚举类,存储业务逻辑的code和msg
package com.oysept.bean;
/**
* 全局统一返回code与msg
* @author ouyangjun
*/
public enum CodeEnum {
RESULT_CODE_SUCCESS("S0000000", "SUCCESS"),
RESULT_CODE_FAIL("F0000000", "FAIL"),
;
private String code;
private String msg;
CodeEnum(String code, String msg) {
this.code = code;
this.msg = msg;
}
public String getCode() {return code;}
public void setCode(String code) {this.code = code;}
public String getMsg() {return msg;}
public void setMsg(String msg) {this.msg = msg;}
}
第二步:创建一个统一返回格式,包括状态码、返回消息、返回数据、返回时间(可自行扩展)
package com.oysept.bean;
import java.io.Serializable;
import java.util.Date;
/**
* 全局返回Result
* @author ouyangjun
*/
public class Result<T> implements Serializable {
private static final long serialVersionUID = 1L;
private String code;
private String msg;
private T data;
private Date time;
public Result() {}
public Result(CodeEnum codeenum, T data) {
this.code = codeenum.getCode();
this.msg = codeenum.getMsg();
this.data = data;
this.time = new Date();
}
public Result(String code, String msg, T data) {
this.code = code;
this.msg = msg;
this.data = data;
this.time = new Date();
}
public String getCode() {return code;}
public void setCode(String code) {this.code = code;}
public String getMsg() {return msg;}
public void setMsg(String msg) {this.msg = msg;}
public T getData() {return data;}
public void setData(T data) {this.data = data;}
public Date getTime() {return time;}
public void setTime(Date time) {this.time = time;}
}
第三步:创建一个实体类,用于传值
package com.oysept.bean;
import java.io.Serializable;
public class ParamsVO implements Serializable {
private static final long serialVersionUID = 1L;
private String id;
private String name;
public String getId() {return id;}
public void setId(String id) {this.id = id;}
public String getName() {return name;}
public void setName(String name) {this.name = name;}
}
四)RESTful GET传参与返回值
引入的类,下面GET和POST方法需要用到:
package com.oysept.controller;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.oysept.bean.CodeEnum;
import com.oysept.bean.ParamsVO;
import com.oysept.bean.Result;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
public class RestfulController {
// GET 或 POST请求代码, 代码如下
}
GET请求可直接打开浏览器,直接输入地址访问。
第一种:无参数GET请求
// 访问地址: http://localhost:8080/restful/get/noParamsGET
@RequestMapping(value="/restful/get/noParamsGET", method = RequestMethod.GET)
@ResponseBody
public Result<String> noParamsGET() {
String data = "noParamsGET,无参数GET请求";
return new Result<String>(CodeEnum.RESULT_CODE_SUCCESS, data);
}
第二种:带参数GET请求,通过HttpServletRequest.getParameter("")方法获取参数
// 访问地址: http://localhost:8080/restful/get/httprequestGET?id=666&name=ouyangjun
@RequestMapping(value="/restful/get/httprequestGET", method = RequestMethod.GET)
@ResponseBody
public Result<String> httprequestGET(HttpServletRequest request, HttpServletResponse response) {
// 如果id为空, 会报空指针错误
String id = request.getParameter("id");
if (id == null || "".equals(id)) {
return new Result<String>(CodeEnum.RESULT_CODE_FAIL, "id is null!");
}
String name = request.getParameter("name");
String data = "requestGET, id: " + id + ", name: " + name;
return new Result<String>(CodeEnum.RESULT_CODE_SUCCESS, data);
}
第三种:带参数GET请求,在路径中传值,参数名称需保持一致
// 访问地址: http://localhost:8080/restful/get/oneParamsGET?id=666
@RequestMapping(value="/restful/get/oneParamsGET", method = RequestMethod.GET)
@ResponseBody
public Result<String> oneParamsGET(String id) {
String data = "oneParamsGET, id: " + id;
return new Result<String>(CodeEnum.RESULT_CODE_SUCCESS, data);
}
第四种:带参数GET请求,多个参数传值
// 访问地址: http://localhost:8080/restful/get/twoParamsGET?id=111&name=oysept
@RequestMapping(value="/restful/get/twoParamsGET", method = RequestMethod.GET)
@ResponseBody
public Result<String> twoParamsGET(String id, String name) {
String data = "id: " + id + ", name: " + name;
return new Result<String>(CodeEnum.RESULT_CODE_SUCCESS, data);
}
第五种:GET请求,指定参数的名称,然后可以取别名
// 访问地址: http://localhost:8080/restful/get/requestParamGET?id=111&name=oysept
@RequestMapping(value="/restful/get/requestParamGET", method = RequestMethod.GET)
@ResponseBody
public Result<String> requestParamGET(@RequestParam("id") String aaa, @RequestParam("name") String bbb) {
String data = "aaa: " + aaa + ", bbb: " + bbb;
return new Result<String>(CodeEnum.RESULT_CODE_SUCCESS, data);
}
第六种:GET请求,把参数作为路径中的一部分传值
// 访问地址: http://localhost:8080/restful/get/666/ouyangjun
@RequestMapping(value="/restful/get/{id}/{name}", method = RequestMethod.GET)
@ResponseBody
public Result<String> pathGET(@PathVariable("id") String aaa, @PathVariable("name") String bbb) {
String data = "aaa: " + aaa + ", bbb: " + bbb;
return new Result<String>(CodeEnum.RESULT_CODE_SUCCESS, data);
}
第七种:GET方式,form表单传值
// 访问地址: http://localhost:8080/restful/get/noParamsObject
@RequestMapping(value="/restful/get/noParamsObject", method = RequestMethod.GET)
@ResponseBody
public Result<ParamsVO> noParamsObject() {
ParamsVO vo = new ParamsVO();
vo.setId("123");
vo.setName("GOOD");
return new Result<ParamsVO>(CodeEnum.RESULT_CODE_SUCCESS, vo);
}
五)RESTful POST传参与返回值
POST请求不能直接在地址栏访问,可借助Postman工具,网上很多这种http请求软件。
第一种:POST无参数请求
// 访问地址: http://localhost:8080/restful/post/noParamsPost
@RequestMapping(value="/restful/post/noParamsPost", method = RequestMethod.POST)
@ResponseBody
public Result<String> noParamsPost() {
String data = "noParamsPost,无参数POST请求";
return new Result<String>(CodeEnum.RESULT_CODE_SUCCESS, data);
}
第二种:form表单,POST方式传值
// 表单请求参数方式
// 访问地址: http://localhost:8080/restful/post/reqFormPOST
@RequestMapping(value="/restful/post/reqFormPOST", method = RequestMethod.POST)
@ResponseBody
public Result<ParamsVO> reqFormPOST(ParamsVO vo) {
if (vo == null) {
return new Result<ParamsVO>(CodeEnum.RESULT_CODE_FAIL, new ParamsVO());
}
return new Result<ParamsVO>(CodeEnum.RESULT_CODE_SUCCESS, vo);
}
效果图:
第三种:JSON方式,POST请求集合参数
// json方式
// 访问地址: http://localhost:8080/restful/post/reqBodysParamsPOST
@RequestMapping(value="/restful/post/reqBodysParamsPOST", method = RequestMethod.POST)
@ResponseBody
public Result<List<String>> reqBodysParamsPOST(@RequestBody List<String> ids) {
if (ids == null || ids.size()==0) {
return new Result<List<String>>(CodeEnum.RESULT_CODE_FAIL, new ArrayList<String>());
}
return new Result<List<String>>(CodeEnum.RESULT_CODE_SUCCESS, ids);
}
第四种:JSON方式,POST请求对象参数
// json方式
// 访问地址: http://localhost:8080/restful/post/reqBodysObjectPOST
@RequestMapping(value="/restful/post/reqBodysObjectPOST", method = RequestMethod.POST)
@ResponseBody
public Result<ParamsVO> reqBodysObjectPOST(@RequestBody ParamsVO vo) {
if (vo == null) {
return new Result<ParamsVO>(CodeEnum.RESULT_CODE_FAIL, new ParamsVO());
}
return new Result<ParamsVO>(CodeEnum.RESULT_CODE_SUCCESS, vo);
}
效果图:
六)重定向和请求转发
项目启动之后,可直接在浏览器输入地址进行访问。
package com.oysept.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
public class LocationController {
// 重定向地址
@RequestMapping("/restful/returnMessage")
@ResponseBody
public String returnMessage () {
return "测试重定向or请求转发, 返回message!";
}
// 测试请求转发地址: http://localhost:8080/restful/forward/req
@RequestMapping("/restful/forward/req")
public String forwardReq () {
// 地址之间不能有空格
return "forward:/restful/returnMessage";
}
// 测试重定向地址: http://localhost:8080/restful/redirect/req
@RequestMapping("/restful/redirect/req")
public String redirectReq () {
// 地址之间不能有空格
return "redirect:/restful/returnMessage";
}
}
七)附件下载方式
该方式适合各种字节流对文件进行远程下载,http或https的地址都可以。
第一步:传入HttpServletResponse对象。
第二步:设置附件信息,比如附件名、附件编码等。
第三步:获取附件的ContentType类型,附件下载时,需要指定转换成的文件类型。(已列举常用类型)
第四步:通过http或https获取远程附件流。
第五步:把附件下载到本地指定路径。
源码:
package com.oysept.controller;
import com.oysept.bean.ParamsVO;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLDecoder;
@Controller
public class DownloadController {
// 返回响应报文, 适合各种类型文件下载
// 请求地址: http://localhost:8080/restful/file/download
@RequestMapping(value = "/restful/file/download", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
public void urlDownload(@RequestBody ParamsVO vo, HttpServletResponse response) {
// 打印对象中的参数信息
System.out.println("id: " + vo.getId() + ", name: " + vo.getName());
try {
String filename = "baidu.html";
// 设置附件信息,fileName中如果包含中文,可能会出现乱码
response.setHeader("Content-disposition", "attachment; filename=" + URLDecoder.decode(filename, "UTF-8"));
response.setCharacterEncoding("utf-8");
response.setContentType(getResponseContentType("html")); // 不同的文件类型,有不同的ContentType, 如需动态指定类型, 可截取附件的后缀
BufferedInputStream bufferInput = null; // 字节缓存输入流
BufferedOutputStream bufferOutput = null; // 字节缓存输出流
try {
InputStream in = getHttpInputStream("https://www.baidu.com/", "GET");
bufferInput = new BufferedInputStream(in);
OutputStream out = response.getOutputStream();
bufferOutput = new BufferedOutputStream(out);
int l = -1;
byte[] tmp =new byte[1024];
while ((l = bufferInput.read(tmp)) != -1) {
bufferOutput.write(tmp, 0, l);
}
} catch (FileNotFoundException e) {
System.out.println("/restful/file/download!" + e);
} catch (IOException e) {
System.out.println("/restful/file/download!" + e);
} finally {
// 关闭低层流。
try {
if (bufferInput != null) {
bufferInput.close();
}
if (bufferOutput != null){
bufferOutput.close();
}
} catch (IOException e) {
System.out.println("/restful/file/download!" + e);
}
}
} catch (UnsupportedEncodingException e) {
System.out.println("/restful/file/download!" + e);
}
}
/**
* 获取HttpServletResponse设置的ContentType参数
* @return
*/
public String getResponseContentType(String type) {
String contentType = null;
if ("xlsx,xls,docx,doc,pptx,ppt,dotx,docm,dotm,xltx,xlsm,xltm,xlam,xlsb,potx,ppsx,ppam,pptm,potm,ppsm,xlt,xla,pot,pps,ppa"
.contains(type)) {
// 附件header处理
if("xlsx".equals(type)) {
contentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8";
} else if("xls".equals(type) || "xlt".equals(type) || "xla".equals(type)) {
contentType = "application/vnd.ms-excel;charset=utf-8";
} else if("docx".equals(type)) {
contentType = "application/vnd.openxmlformats-officedocument.wordprocessingml.document;charset=utf-8";
} else if("doc".equals(type) || "dot".equals(type)) {
contentType = "application/msword;charset=utf-8";
} else if("pptx".equals(type)) {
contentType = "application/vnd.openxmlformats-officedocument.presentationml.presentation;charset=utf-8";
} else if("ppt".equals(type) || "pot".equals(type) || "pps".equals(type) || "ppa".equals(type)) {
contentType = "application/vnd.ms-powerpoint;charset=utf-8";
} else if("dotx".equals(type)) {
contentType = "application/vnd.openxmlformats-officedocument.wordprocessingml.template;charset=utf-8";
} else if("docm".equals(type)) {
contentType = "application/vnd.ms-word.document.macroEnabled.12;charset=utf-8";
} else if("dotm".equals(type)) {
contentType = "application/vnd.ms-word.template.macroEnabled.12;charset=utf-8";
} else if("xltx".equals(type)) {
contentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.template;charset=utf-8";
} else if("xlsm".equals(type)) {
contentType = "application/vnd.ms-excel.sheet.macroEnabled.12;charset=utf-8";
} else if("xltm".equals(type)) {
contentType = "application/vnd.ms-excel.template.macroEnabled.12;charset=utf-8";
} else if("xlam".equals(type)) {
contentType = "application/vnd.ms-excel.addin.macroEnabled.12;charset=utf-8";
} else if("xlsb".equals(type)) {
contentType = "application/vnd.ms-excel.sheet.binary.macroEnabled.12;charset=utf-8";
} else if("potx".equals(type)) {
contentType = "application/vnd.openxmlformats-officedocument.presentationml.template;charset=utf-8";
} else if("ppsx".equals(type)) {
contentType = "application/vnd.openxmlformats-officedocument.presentationml.slideshow;charset=utf-8";
} else if("ppam".equals(type)) {
contentType = "application/vnd.ms-powerpoint.addin.macroEnabled.12;charset=utf-8";
} else if("pptm".equals(type)) {
contentType = "application/vnd.ms-powerpoint.presentation.macroEnabled.12;charset=utf-8";
} else if("potm".equals(type)) {
contentType = "application/vnd.ms-powerpoint.template.macroEnabled.12;charset=utf-8";
} else if("ppsm".equals(type)) {
contentType = "application/vnd.ms-powerpoint.slideshow.macroEnabled.12;charset=utf-8";
}
} else if ("txt".equals(type)) {
contentType = "text/plain;charset=utf-8";
} else if ("pdf".equals(type)) {
contentType = "application/pdf;charset=utf-8";
} else if ("png".equals(type)) {
contentType = "image/png;charset=utf-8";
} else if ("jpg".equals(type) || "jpeg".equals(type)) {
contentType = "image/jpeg;charset=utf-8";
} else if ("bmp".equals(type)) {
contentType = "application/x-bmp;charset=utf-8";
} else if ("gif".equals(type)) {
contentType = "image/gif;charset=utf-8";
} else if ("html".equals(type) || "htm".equals(type)) {
contentType = "text/html;charset=utf-8";
} else if ("xml".equals(type)) {
contentType = "text/xml;charset=utf-8";
} else if ("css".equals(type)) {
contentType = "text/css;charset=utf-8";
} else if ("js".equals(type)) {
contentType = "application/x-javascript;charset=utf-8";
} else if ("eml".equals(type)) {
contentType = "message/rfc822;charset=utf-8";
} else if ("xlw".equals(type)) {
contentType = "application/x-xlw;charset=utf-8";
} else if ("ai".equals(type)) {
contentType = "application/postscript;charset=utf-8";
} else if ("rtf".equals(type)) {
contentType = "application/msword;charset=utf-8";
} else if ("mp4".equals(type)) {
contentType = "video/mpeg4;charset=utf-8";
} else if ("tif".equals(type) || "tiff".equals(type)) {
contentType = "image/tiff;charset=utf-8";
} else if ("exe".equals(type)) {
contentType = "application/x-msdownload;charset=utf-8";
} else if ("pls".equals(type)) {
contentType = "audio/scpls;charset=utf-8";
} else if ("rpm".equals(type)) {
contentType = "audio/x-pn-realaudio-plugin;charset=utf-8";
} else if ("mht".equals(type)) {
contentType = "message/rfc822;charset=utf-8";
}
return contentType;
}
/**
* http获取InputStream
* @param requestUrl: 请求路径
* @param requestMethod: 请求方式(GET、POST)
* @return
*/
public InputStream getHttpInputStream(String requestUrl, String requestMethod) {
HttpURLConnection con = null;
InputStream is = null;
try {
URL url = new URL(requestUrl);
// 原生访问http请求,未代理请求
con = (HttpURLConnection) url.openConnection();
con.setDoOutput(true);
con.setDoInput(true);
con.setUseCaches(false);
con.setRequestMethod(requestMethod);
con.setReadTimeout(60000);
con.setConnectTimeout(60000);
con.connect();
// 获取InputStream
is = con.getInputStream();
return is;
} catch (IOException e) {
System.out.println("getHttpInputStream error!" + e);
}
return null;
}
}
原文链接:https://blog.csdn.net/p812438109/article/details/106629526