寫在前面:
因?yàn)槲沂亲龊蠖说模噪y免會從后端的角度來思考問題。關(guān)于交互的設(shè)計其實(shí)是通過后端去控制前端。
這個怎么說呢,雖然都在強(qiáng)調(diào)前后端的松耦合,后端不應(yīng)該涉足前端頁面相關(guān)的東西。但是在小項(xiàng)目中,實(shí)際上都是后端占程序結(jié)構(gòu)的主導(dǎo)地位,所以說,以后臺去控制前端可以避免很多交互上的麻煩,可以從一定程度上減小交互格式的爭論。
說了這么多沒用的,現(xiàn)在開始來看代碼。
核心類:
/** * Created by liuruijie on 2016/9/28.
* 前端頁面控制
*/
public class WebResult {
private String status; //狀態(tài)碼
private String msg; //提示信息
private String redirectUrl; //重定向的url
private boolean back; //返回
private boolean refresh; //刷新頁面
private Map<String, Object> data; //數(shù)據(jù)
public WebResult(){
data = new HashMap<>();
refresh = false;
back = false;
status = Config.SUCCESS;
}
public static WebResult buildResult(){
return new WebResult();
}
public WebResult status(String status){
setStatus(status);
return this;
}
public WebResult msg(String msg){
setMsg(msg);
return this;
}
public WebResult redirectUrl(String redirectUrl){
setRedirectUrl(redirectUrl);
return this;
}
public WebResult back(){
setBack(true);
return this;
}
public WebResult refresh(){
setRefresh(true);
return this;
}
public WebResult putData(String name, Object val){
data.put(name, val);
return this;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
public Map<String, Object> getData() {
return data;
}
public void setData(Map<String, Object> data) {
this.data = data;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public String getRedirectUrl() {
return redirectUrl;
}
public void setRedirectUrl(String redirectUrl) {
this.redirectUrl = redirectUrl;
}
public boolean isRefresh() {
return refresh;
}
public void setRefresh(boolean refresh) {
this.refresh = refresh;
}
public boolean isBack() {
return back;
}
public void setBack(boolean back) {
this.back = back;
}
}
這其實(shí)是一個簡單的javabean,但是在其中添加了一些方便的鏈?zhǔn)皆O(shè)置屬性的方法。我可以通過這個類來控制前端的跳轉(zhuǎn)、彈框、刷新、返回以及跳轉(zhuǎn)等。使用方式也很簡單:
首先需要Controller的交互方法都是加了@ResponseBody的,因?yàn)樾枰獙⒎祷刂敌蛄谢癁閖son格式字符串。
一個簡便的方法是在Controller的類上使用@RestController代替@Controller,這樣其每個方法默認(rèn)都加上了@ResponseBody。
@RestController
@RequestMapping("student")
public class StudentController{
//...
}
//刷新
return WebResult.buildResult().refresh();
//返回上個頁面
return WebResult.buildResult().back();
//發(fā)送數(shù)據(jù)
return WebResult.buildResult().putData("user", user);
//。。。
當(dāng)然只有WebResult類還是不夠的。它的作用相當(dāng)于只是提供了一個規(guī)范,一個前后端都必須遵守的規(guī)范。前端也需要對其進(jìn)行實(shí)現(xiàn)才能達(dá)到真正的效果。
來看前端的js代碼:
/**
* Created by liuruijie on 2016/9/28.
* 前端控制
*/
//狀態(tài)碼
web_status = {
SUCCESS : "000",
FAIL : "001",
NO_LOGIN : "003",
NO_PRIVILEGE : "004"
};
function simpleSuccess(result) {
//如果成功,則讀取后端返回的操作指令
if (result.status == web_status.SUCCESS) {
//刷新
if(result['refresh']){
window.location.reload();
return;
}
//返回
if(result['back']){
window.location.href = document.referrer;
}
//跳轉(zhuǎn)
if(result['redirectUrl']!=null){
window.location.href = result.redirectUrl;
return;
}
return result.data;
}
//未登錄
if (result.status == web_status.NO_LOGIN) {
alert("您還未登陸!");
window.location.href = "/bpm/login";
}else{
//其他錯誤情況,直接彈出提示框
if(result.msg!=null){
alert(result.msg);
}
}
return null;
}
//對jquery的ajax方法再次封裝
__ajax = function(url, data, success, type){
success = success||function(data){};
data = data||{};
$.ajax({
url:url,
type:type,
dataType:"json",
data:data,
success:function(result){
success(simpleSuccess(result));
}
})
};
//再再次封裝
AJAX = {
GET:function(url, data, success){
__ajax(url, data, success, "get");
},
POST: function(url, data, success){
__ajax(url, data, success, "post");
},
DELETE: function(url, data, success){
__ajax(url, data, success, "delete");
},
PUT:function(url, data, success){
__ajax(url, data, success, "put");
};
其中狀態(tài)碼要對應(yīng)后端的狀態(tài)碼,后端的狀態(tài)碼可以以常量的方式配置在一個單獨(dú)的類中。
/**
* 系統(tǒng)基礎(chǔ)參數(shù)定義
*/
public class Config {
//狀態(tài)碼
public final static String SUCCESS = "000";
public final static String FAIL = "001";
public final static String NO_LOGIN = "003";
public final static String NO_PRIVILEGE = "004";
}
狀態(tài)碼的值無所謂,只需要對應(yīng)就行了。
一般的使用方式:
//登陸
AJAX.POST("/passport/login", {
username:name,
password:psw
})
//查詢
AJAX.GET("/student/1",null,function(data){
var studentinfo = data.student;
//將學(xué)生信息顯示的頁面相關(guān)操作
//do sth.
});
//刪除
AJAX.DELETE("/student/1");
//更新
AJAX.PUT("/student/1", {code:"111",name:"lrj",classCode:"1301403"})
可以看到,現(xiàn)在交互的前端部分,完全沒有任何異常處理之類的代碼,因?yàn)檫@些已經(jīng)定義好了,所以現(xiàn)在前端只需要關(guān)心,頁面怎么顯示,怎么輸出,不需要關(guān)心出錯之后的彈框、跳轉(zhuǎn)、刷新等等。
到此,前后端交互部分的設(shè)計已經(jīng)基本完成。
相對完整的使用例子:
登陸的前臺代碼:
AJAX.POST("/passport/login", {
username:name,
password:psw
})
登陸的后臺代碼:
@RequestMapping("login")
public Object doLogin(String username, String password){
User user = passportService.doLogin(username, password);
if(user==null){
return WebResult.buildResult().msg("用戶名或密碼錯誤");
}else{
return WebResult.buildResult().redirectUrl("/student/index");
}
}
這樣前端完全不用管返回值,還有操作是否成功之類的,因?yàn)檫@些已經(jīng)提前規(guī)范好了。
但是現(xiàn)在后臺部分還有問題,因?yàn)楹笈_部分的代碼還是顯得很不優(yōu)雅。那么在下一節(jié)就著重設(shè)計后臺代碼,讓后臺的異常處理也變的簡單,精簡代碼量。