如何利用異常在service層向外拋出具體的錯誤信息而又儘可能少建立異常類

後臺服務化以後,服務之間的調用變得很頻繁,每個接口的調用會有多個不一樣的返回值,有些返回值咱們能夠直接在後臺處理,有些返回值我應該返回到終端用戶進行處理。java

這就要求咱們在處理返回值和異常的時候須要仔細考慮了。redis

個人處理方式是:app

一、咱們能夠在後臺處理的返回信息,就用方法返回值處理,不用拋出異常的方式返回。異步

      好比,用戶登陸的時候,去查詢用戶中心,沒有查到用戶記錄,用戶中心返回null, 這個時候咱們就要本身處理這個返回值,應該是打個日誌,而後給終端返回登陸信息錯誤的提示。ide

二、咱們在後臺處理不了,必須拋到終端用戶發起請求的地方進行處理的狀況咱們就用拋出異常的方式。而後咱們在調用接口的地方捕捉異常,而後統一打日誌,而後直接輸出錯誤提示到終端。this

 

第一點沒有任何問題,相信多數都這麼作的,可是第二點就有點麻煩了。若是咱們在每一個地方都拋異常,相似於jdk裏面,對每一種錯誤都定義一個異常,那咱們得定義多少異常呢。固然,若是你願意定義這麼多異常也能夠。只是會比較麻煩而已。日誌

個人解決辦法以下:code

咱們在輸出數據到終端的時候格式通常是 {code:1,data:"",msg:"success"} 這樣子的。那咱們在調用服務化的接口時拋出的異常咱們就想辦法讓它自動轉化成這種格式。下面看代碼。對象

第一步,定義少許的異常,我這裏只對每一個服務定義一個異常類。好比,對整個用戶中心就只定義一個異常類。而後全部用戶中心服務返回時若是有異常拋出,都使用這一個異常類。token

package com.***.common.exception;

import java.io.IOException;
import java.io.Serializable;

public class UserServiceException extends IOException implements Serializable {

    private static final long serialVersionUID = 5848657787701620781L;

    private String code;

    private String codeMsg;

    public UserServiceException(String code, String codeMsg, final String exceptinMessage) {
        super(exceptinMessage);
        this.code = code;
        this.codeMsg = codeMsg;
    }

    public UserServiceException(int code, String codeMsg, final String message) {
        super(message);
        this.code = code + "";
        this.codeMsg = codeMsg;
    }
    
    public UserServiceException(int code, String codeMsg) {
        super(codeMsg);
        this.code = code + "";
        this.codeMsg = codeMsg;
    }

    public String getCode() {
        return code;
    }

    public String getCodeMsg() {
        return codeMsg;
    }

}

第二步,調用接口的代碼。

/**
	 * 驗證碼登陸
	 * @return
	 */
	@ResponseBody
	@RequestMapping(value="codeLogin", method = {RequestMethod.POST,RequestMethod.GET})
	public Object  codeLogin(HttpServletRequest request, HttpServletResponse response,String mobile, String code){
		
		if(StringUtil.trimToNull(mobile)==null
				||StringUtil.trimToNull(code)==null){
			log.info("登陸參數不正確,mobile={},code={}",mobile,code);
			return new DataResult(DataCodes.PARAMETER_EMPTY_ERROR, DataCodes.PARAMETER_EMPTY_MSG);
		}
		try {
                        //接口調用
			UserApi user = userApiService.codeLogin(mobile,code);
			if(user==null){
				return new DataResult(DataCodes.CODE_ERROR,DataCodes.CODE_ERROR_MSG);
			}
			writeCookie(request, response, user.getToken());
			Map<String,Object> map = new HashMap<String,Object>();
			map.put("nickname", user.getNickname());
			map.put("head", user.getPhoto());
			map.put("status", user.getStatus());
			
			return new DataResult(map);
		}
		catch (UserServiceException e) {
                     //用戶中心可能拋出不一樣的錯誤信息,可是都是利用同一個異常類拋出,關鍵在於裏面的code是什麼。
			log.info("登陸調用service出錯,message={}",e.getMessage());
                     //異常信息裏面帶有code,能夠直接輸出到終端,終端會看到提示和code代碼。
			return new DataResult(e.getCode(), e.getCodeMsg());
		}
		catch (Exception e) {
			log.error("登陸錯誤",e);
                        //這個異常捕捉必需要有
			return new DataResult(DataCodes.SYSTEM_ERROR, DataCodes.SYSTEM_ERROR_MSG);
		}
		
	}

 

第三步, 接口返回不一樣信息給接口調用者。記住本身要寫一個常量類,用來保存全部的code和msg。而後正常返回和錯誤返回都是調用同一個常量類的code和msg。

@Override
	public UserApi codeLogin(String mobile, String code) throws UserServiceException {
		
		String loginCode = (String)redisTemplate.opsForValue().get(RedisKeys.LOGIN_KEY+mobile);
		if(loginCode==null ||  !loginCode.equals(code)){
			log.error("驗證碼不存在,mobile={},code={},loginCode={}",mobile,code,loginCode);
                       //錯誤返回,實例化一個異常類的對象,而且設置好code和msg,返回拋出。
			throw new UserServiceException(DataCodes.CODE_ERROR,DataCodes.CODE_ERROR_MSG,DataCodes.CODE_ERROR_MSG);
		}
		//清除驗證碼
		redisTemplate.delete(RedisKeys.LOGIN_KEY+mobile);
		
		UserDbo userDb =   userDao.getUserByMobile(mobile);
		
		if(userDb==null){
			log.error("驗證碼登陸失敗,mobile不存在,mobile={},code={},loginCode={}",mobile,code,loginCode);
                       //錯誤返回,實例化一個異常類的對象,而且設置好code和msg,返回拋出。
			throw new UserServiceException(DataCodes.MOBILE_NOT_EXIST_ERROR,DataCodes.MOBILE_NOT_EXIST_ERROR_MSG,DataCodes.MOBILE_NOT_EXIST_ERROR_MSG);
		}
		
		//更新 token
		long tokenTime = System.currentTimeMillis();
		String token =。。。。。;//省略掉了
		
		//異步更新
		executeUpdateToken.execute(new UpdateTokenThread(userDb.getId(), token, tokenTime, userExtDao,true));
		
		UserApi user = new UserApi();
//		user.setToken(token);
		user.setAccount(userDb.getAccount());
		user.setStatus(userDb.getStatus());
		user.setNickname(userDb.getNickname());
		
		return user;//正常返回
	}

 

這樣,咱們就能夠處理各類不一樣返回的狀況了,並且只定義少許的異常類,卻可以知足全部的接口調用的返回處理。

相關文章
相關標籤/搜索