一、RESTful

RESTful,一种通用的前后台交互方式

RESTful一般是指这种格式:

(1)使用HTTP POST(或GET)进行数据交互

(2)请求数据和应答数据均为JSON格式(或XML)

二、RESTful接口的实现

RESTful的前端实现

前端:在发送请求时,把请求转成JSON字符串

$.ajax({
				type:"POST",    /*请求类型-POST/GET*/
				url:"AddStudent?mode=admin&token=12930289",   /*服务URI,用相对地址*/
				data:jsonStr,          /*附加请求参数*/
				dataType:"json",   /*期望服务器返回的数据类型*/
				success: function(resp)  /*已经将服务器返回的数据转成JS 对象*/
				{
					if(resp.error==0)
					alert("提交成功");
					else
					alert("出错:"+resp.reason);
				},
				error: function(jqXHR, textstatus, errorThrown)
				{
					alert("错误:" +jqXHR.status);
				}
			});	

后端:手工读取请求数据,转成JSONObject,然后再做处理

//读取请求数据,转化为字符串
String reqText = readAsText(request.getInputStream(), "utf-8");
		
//转化为json
JSONObject jreq = new JSONObject(reqText);

三、RESTful附加URL参数

一般来说,使用RESTful接口时,所有的请求参数放在JSON中即可。但有的时候,还有少许参数放在URL里面。

演示代码:

前端:

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title>AJAX POST</title>
		<script type="text/javascript" src="JS/jquery-3.3.1.min.js"></script>
		
		<style>
			.main
			{
				width: 500px;
				margin: 10px auto;    		
			}
			.main input,select{
				width: 250px;
				padding: 4px;
				margin: 2px;
			}
		</style>
	</head>
	<body>
		<div class="main">
			学号: <input type='text' class='id' />  <br>  <!-- name: 即参数名 -->
	    	姓名: <input type='text' class='name' /> <br>
	    	手机: <input type='text' class='phone' /> <br>
	    	性别: <select class='sex' style="width: 260px;">
	    		<option value='male'> 男 </option>
	    		<option value='female'> 女 </option>
	    	</select> <br><br>
	    	<button onclick="submit()">提交</button>
		</div>
	</body>
	<script>
		function submit()
		{
			var req = {};
			
			req.id = $(".main .id").val().trim();
			req.name = $(".main .name").val().trim();
			req.phone = $(".main .phone").val().trim();
			req.sex = $(".main .sex").val().trim();
			
			/*在发送请求时,把请求转成json对象*/
			var jsonStr = JSON.stringify(req);
			console.log(jsonStr);
			
			$.ajax({
				type:"POST",    /*请求类型-POST/GET*/
				url:"AddStudent?mode=admin&token=12930289",   /*服务URI,用相对地址*/
				data:jsonStr,          /*附加请求参数*/
				dataType:"json",   /*期望服务器返回的数据类型*/
				success: function(resp)  /*已经将服务器返回的数据转成JS 对象*/
				{
					if(resp.error==0)
					alert("提交成功");
					else
					alert("出错:"+resp.reason);
				},
				error: function(jqXHR, textstatus, errorThrown)
				{
					alert("错误:" +jqXHR.status);
				}
			});	
		}
	</script>
</html>

后端核心代码:

package my;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.Writer;
import java.util.HashMap;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.json.JSONObject;

/**
 * Servlet implementation class AddStudent
 */
@WebServlet("/AddStudent")
public class AddStudent extends HttpServlet {
	private static final long serialVersionUID = 1L;
       
    /**
     * @see HttpServlet#HttpServlet()
     */
    public AddStudent() {
        super();
        // TODO Auto-generated constructor stub
    }

	/**
	 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// TODO Auto-generated method stub
		response.getWriter().append("Served at: ").append(request.getContextPath());
	}

	/**
	 * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doPost(HttpServletRequest request, HttpServletResponse response) 
								throws ServletException, IOException {
		String reqText = readAsText(request.getInputStream(), "UTF-8");
		
		System.out.println(reqText);
		
		//转化为JSON
		JSONObject jreq = new JSONObject(reqText);
		
		//URL末尾,由问号引导的字符串(在restful中也有部分参数在URL中
		//例如:url:"AddStudent?mode=admin&token=12930289",   /*服务URI,用相对地址*/
		String query = request.getQueryString();
		System.out.println(query);
		HashMap<String, String>ppp = parseQuery(query);
		System.out.println(ppp);
		
		int id = jreq.getInt("id");
		String name = jreq.getString("name");
		String phone = jreq.getString("phone");
		boolean sex = "male".equals(jreq.getString("sex")); 
		
		// 添加到数据库
		Student s = new Student(id, name, sex, phone);
		DemoDB.i.add( s );
		
		// 返回应答数据
		JSONObject jresp = new JSONObject();
		jresp.put("error", 0); // 错误码,0表示成功
		jresp.put("reason", "OK"); // 错误原因描述, 如果没有错误则提示OK
		response.setCharacterEncoding("UTF-8");
		response.setContentType("text/plain");
		Writer writer = response.getWriter();
		writer.write( jresp.toString(2));
		writer.close();
		
	}
	
	//从Stream中读取数据直到读取完毕
	public String readAsText(InputStream StreamIn, String charset) throws IOException
	{
		ByteArrayOutputStream cache = new ByteArrayOutputStream(1024*16);
		byte[] data = new byte[1024];
		
		while(true)
		{
			int n =StreamIn.read(data);
			if(n<0)break;
			if(n==0)continue;
			
			//缓存起来
			cache.write(data, 0 ,n);
			if(cache.size()>1024*512)
				break;
		}
		
		return cache.toString(charset);
	}
	
	//转为HashMap
	public HashMap<String, String>parseQuery(String query)
	{
		HashMap<String, String>parms = new HashMap<String, String>();
		
		String[] ppp = query.split("&");
		
		for(String p : ppp)
		{
			String[] kv = p.split("=");
			
			String key = kv[0];
			String value = "";
			if(kv.length>1)value = kv[1];
			
			parms.put(key, value);
		}
		
		return parms;
	}

}

四、快速创建REST服务

-首先自定义设计一个抽象类AfSimpleREST继承与HttpServlet

-里面定义一个抽象方法,用于子类对前端传回的JSON格式字符串的数据进行分析

package my;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.Writer;


import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.json.JSONObject;

import af.AfWebException;

public abstract class AfSimpleREST extends HttpServlet
{
	protected boolean enableErrorLog = false; // 是否打印异常输出
	protected boolean niceJSONFormat = true; // 输出的JSON是否综进 (缩进影响运行效率)
	protected int MAX_REQUEST_SIZE = 1024 * 512; // 允许上传的JSON最大长度
	protected String charset = "UTF-8";
	
	// 子类须重写这个方法,进行业务处理
	// 处理返回后,可以返回 JSONObject, JSONArray, 或int long String 等基本类型
	protected abstract Object execute(HttpServletRequest request,
											HttpServletResponse response,
											JSONObject jreq)throws Exception;

	@Override
	protected void doGet(HttpServletRequest request, HttpServletResponse response) 
										throws ServletException, IOException
	{
		// 无论是 GET/POST, 均统一处理
		doPost(request, response);
	}

	@Override
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
	{
		String requestURI = request.getRequestURI();
		
		
		// 处理请求数据
		JSONObject jresp = new JSONObject();		
		try{
			// 读取请求数据, 转成字符串, 转成 JSON
			String reqText = readAsText(request.getInputStream(), charset, MAX_REQUEST_SIZE);
			JSONObject jreq = null;
			if(reqText.length()>0) jreq = new JSONObject(reqText);
			
			// 子类应重写 execute() 方法
			Object data = execute(request, response, jreq);
			jresp.put("error", 0); // 错误码,0表示成功
			jresp.put("reason", "OK"); // 错误原因描述, 如果没有错误则提示OK
			if(data != null)
				jresp.put("data", data); // 
		}
		catch(AfWebException e)
		{
			String reason = e.getMessage();		
			System.out.println("** 出错: " + requestURI + ", 原因: " + reason);
			
			if(enableErrorLog) e.printStackTrace();
			
			// 应签数据
			jresp.put("error", e.error); // 错误码,0表示成功
			jresp.put("reason", reason); // 错误原因描述, 如果没有错误则提示OK
		}
		catch(Exception e)
		{
			String reason = e.getMessage();
			if(reason == null) reason = e.getClass().getName();			
			System.out.println("** 出错: " + requestURI + ", 原因: " + reason);
			
			if(enableErrorLog) e.printStackTrace();
			
			// 应签数据
			jresp.put("error", -1); // 错误码,0表示成功
			jresp.put("reason", e.getMessage()); // 错误原因描述, 如果没有错误则提示OK
		}
		
		// 是否按可读风格生成JSON ( 缩进格式 or 紧凑格式 )
		String jsonstr = niceJSONFormat ? jresp.toString(2) : jresp.toString();
		
		// 发送应答给客户端
		response.setCharacterEncoding(charset);
		response.setContentType("text/plain");
		//response.setHeader("Connection", "close");
		Writer writer = response.getWriter();
		writer.write( jsonstr );
		writer.close();	
	}
	
	public static String readAsText(InputStream streamIn, String charset, int maxSize)
			throws IOException 
	{
		ByteArrayOutputStream cache = new ByteArrayOutputStream(1024*16);  
        byte[] data = new byte[1024]; 
        
        int numOfWait = 0;
        while (true)
        {
        	int n = streamIn.read(data); // n: 实际读取的字节数
        	if(n < 0) break; // 连接已经断开
        	if(n == 0) 
        	{
        		if( numOfWait ++ >= 3) break; // 此种情况不得连续3次
        		try{ Thread.sleep(5);}catch(Exception e){}
        		continue;// 数据未完 //  
        	}
        	numOfWait = 0;

        	// 缓存起来
        	cache.write(data, 0, n);        	
        	if(cache.size() > maxSize) // 上限, 最多读取512K
        		break;
        }  
        
        return cache.toString(charset);
	}
	

}

子类继承:

package my;

import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.json.JSONObject;

@WebServlet("/AddBook")
public class AddBook extends AfSimpleREST
{

	@Override
	protected Object execute(HttpServletRequest request, 
								HttpServletResponse response, 
									JSONObject jreq) throws Exception
	{
		String id = jreq.getString("id");
		String name = jreq.getString("name");
		String phone = jreq.getString("phone");
		String pub = jreq.getString("pub");
		System.out.println("编号:"+id+"作者:"+name+"手机号:"+phone+"出版社:"+pub);
		return null;
	}

}

前端代码:

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title>AJAX POST</title>
		<script type="text/javascript" src="JS/jquery-3.3.1.min.js"></script>
		
		<style>
			.main
			{
				width: 500px;
				margin: 10px auto;    		
			}
			.main input,select{
				width: 250px;
				padding: 4px;
				margin: 2px;
			}
		</style>
	</head>
	<body>
		<div class="main">
			书号: <br><input type='text' class='id' />  <br>  <!-- name: 即参数名 -->
	    	书名: <br><input type='text' class='name' /> <br>
	    	手机: <br><input type='text' class='phone' /> <br>
	    	出版社: <br><input type='text' class='pub' /> <br><br>
	    	<button onclick="submit()">提交</button>
		</div>
	</body>
	<script>
		function submit()
		{
			var req = {};
			
			req.id = $(".main .id").val().trim();
			req.name = $(".main .name").val().trim();
			req.phone = $(".main .phone").val().trim();
			req.pub = $(".main .pub").val().trim();
			
			/*在发送请求时,把请求转成json对象*/
			var jsonStr = JSON.stringify(req);
			console.log(jsonStr);
			
			$.ajax({
				type:"POST",    /*请求类型-POST/GET*/
				url:"AddBook",   /*服务URI,用相对地址*/
				data:jsonStr,          /*附加请求参数*/
				dataType:"json",   /*期望服务器返回的数据类型*/
				success: function(resp)  /*已经将服务器返回的数据转成JS 对象*/
				{
					if(resp.error==0)
					alert("提交成功");
					else
					alert("出错:"+resp.reason);
				},
				error: function(jqXHR, textstatus, errorThrown)
				{
					alert("错误:" +jqXHR.status);
				}
			});	
		}
	</script>
</html>

 

Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐