国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

Spring Boot實(shí)現(xiàn)高質(zhì)量的CRUD-5

這篇具有很好參考價(jià)值的文章主要介紹了Spring Boot實(shí)現(xiàn)高質(zhì)量的CRUD-5。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問(wèn)。

(續(xù)前文)

9、Service實(shí)現(xiàn)類(lèi)代碼示例 ?

?	以用戶(hù)管理模塊為例,展示Service實(shí)現(xiàn)類(lèi)代碼。用戶(hù)管理的Service實(shí)現(xiàn)類(lèi)為UserManServiceImpl。?UserManServiceImpl除了沒(méi)有deleteItems方法外,具備CRUD的其它常規(guī)方法。實(shí)際上?UserManService還有其它接口方法,如管理員修改密碼,用戶(hù)修改自身密碼,設(shè)置用戶(hù)角色列表,設(shè)置用戶(hù)數(shù)據(jù)權(quán)限等,這些不屬于常規(guī)CRUD方法,故不在此展示。

9.1、類(lèi)定義及成員屬性

?	UserManServiceImpl的類(lèi)定義如下:
package com.abc.example.service.impl;

import java.io.InputStream;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.lang3.RandomStringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import com.github.pagehelper.PageInfo;
import com.abc.esbcommon.common.impexp.BaseExportObj;
import com.abc.esbcommon.common.impexp.BaseImportObj;
import com.abc.esbcommon.common.impexp.ExcelExportHandler;
import com.abc.esbcommon.common.impexp.ExcelImportHandler;
import com.abc.esbcommon.common.impexp.ImpExpFieldDef;
import com.abc.esbcommon.common.utils.FileUtil;
import com.abc.esbcommon.common.utils.LogUtil;
import com.abc.esbcommon.common.utils.Md5Util;
import com.abc.esbcommon.common.utils.ObjListUtil;
import com.abc.esbcommon.common.utils.ReflectUtil;
import com.abc.esbcommon.common.utils.TimeUtil;
import com.abc.esbcommon.common.utils.Utility;
import com.abc.esbcommon.common.utils.ValidateUtil;
import com.abc.esbcommon.entity.SysParameter;
import com.abc.example.common.constants.Constants;
import com.abc.example.config.UploadConfig;
import com.abc.example.dao.UserDao;
import com.abc.example.entity.Orgnization;
import com.abc.example.entity.User;
import com.abc.example.enumeration.EDeleteFlag;
import com.abc.example.enumeration.EIdType;   
import com.abc.example.enumeration.ESex;
import com.abc.example.enumeration.EUserType;
import com.abc.example.exception.BaseException;
import com.abc.example.exception.ExceptionCodes;
import com.abc.example.service.BaseService;
import com.abc.example.service.DataRightsService;
import com.abc.example.service.IdCheckService;
import com.abc.example.service.SysParameterService;
import com.abc.example.service.TableCodeConfigService;
import com.abc.example.service.UserManService;

/**
 * @className	: UserManServiceImpl
 * @description	: 用戶(hù)對(duì)象管理服務(wù)實(shí)現(xiàn)類(lèi)
 * @summary		: 
 * @history		:
 * ------------------------------------------------------------------------------
 * date			version		modifier		remarks
 * ------------------------------------------------------------------------------
 * 2023/05/17	1.0.0		sheng.zheng		初版
 *
 */
@SuppressWarnings({ "unchecked", "unused" })
@Service
public class UserManServiceImpl extends BaseService implements UserManService{
	// 用戶(hù)對(duì)象數(shù)據(jù)訪(fǎng)問(wèn)類(lèi)對(duì)象
	@Autowired
	private UserDao userDao;

    // 文件上傳配置類(lèi)對(duì)象
    @Autowired
    private UploadConfig uploadConfig;

    // 對(duì)象ID檢查服務(wù)類(lèi)對(duì)象
	@Autowired
	private IdCheckService ics;   

	// 數(shù)據(jù)權(quán)限服務(wù)類(lèi)對(duì)象
	@Autowired
	private DataRightsService drs;

	// 全局ID服務(wù)類(lèi)對(duì)象
	@Autowired
	private TableCodeConfigService tccs;
    
    // 系統(tǒng)參數(shù)服務(wù)類(lèi)對(duì)象
	@Autowired
	private SysParameterService sps;

	// 新增必選字段集
	private String[] mandatoryFieldList = new String[]{"userName","password","userType","orgId"};

	// 修改不可編輯字段集
	private String[] uneditFieldList =  new String[]{"password","salt","deleteFlag"};

}
?	UserManServiceImpl類(lèi)繼承BaseService,實(shí)現(xiàn)UserManService接口。BaseService提供參數(shù)校驗(yàn)接口、啟動(dòng)分頁(yè)處理和獲取用戶(hù)賬號(hào)信息的公共方法(參見(jiàn)上文的8.13.1)。
?	UserManServiceImpl類(lèi)成員屬性作用說(shuō)明:
	UserDao userDao:用戶(hù)對(duì)象數(shù)據(jù)訪(fǎng)問(wèn)類(lèi)對(duì)象,用于訪(fǎng)問(wèn)數(shù)據(jù)庫(kù)用戶(hù)表。CRUD操作,與數(shù)據(jù)庫(kù)緊密聯(lián)系,userDao是核心對(duì)象。
	UploadConfig uploadConfig:文件上傳配置類(lèi)對(duì)象,提供臨時(shí)路徑/tmp,導(dǎo)出Excel文件時(shí),生成臨時(shí)文件存于臨時(shí)目錄。上傳Excel文件,臨時(shí)文件也存于此目錄。
	IdCheckService ics:對(duì)象ID檢查服務(wù)類(lèi)對(duì)象,用于外鍵對(duì)象存在性檢查。
	DataRightsService drs:數(shù)據(jù)權(quán)限服務(wù)類(lèi)對(duì)象,提供數(shù)據(jù)權(quán)限處理的相關(guān)接口方法。
	TableCodeConfigService tccs:全局ID服務(wù)類(lèi)對(duì)象,提供生成全局ID的接口方法。
	SysParameterService sps:系統(tǒng)參數(shù)服務(wù)類(lèi)對(duì)象,在Excel數(shù)據(jù)導(dǎo)入導(dǎo)出時(shí),對(duì)枚舉字段的枚舉值翻譯,需要根據(jù)系統(tǒng)參數(shù)表的配置記錄進(jìn)行翻譯。
	String[] mandatoryFieldList:新增必選字段集,新增對(duì)象時(shí),規(guī)定哪些字段是必須的。
	String[] uneditFieldList:不可編輯字段集,編輯對(duì)象時(shí),規(guī)定哪些字段是需要不允許修改的,防止參數(shù)注入。

9.2、新增對(duì)象

?	新增對(duì)象的方法為addItem,下面是新增用戶(hù)對(duì)象的方法:
	/**
	 * @methodName		: addItem
	 * @description		: 新增一個(gè)用戶(hù)對(duì)象
	 * @remark		    : 參見(jiàn)接口類(lèi)方法說(shuō)明
	 * @history			:
	 * ------------------------------------------------------------------------------
	 * date			version		modifier		remarks
	 * ------------------------------------------------------------------------------
	 * 2023/05/17	1.0.0		sheng.zheng		初版
	 *
	 */
	@Override
	public Map<String,Object> addItem(HttpServletRequest request, User item) {
		// 輸入?yún)?shù)校驗(yàn)
		checkValidForParams(request, "addItem", item);

        // 檢查參照ID的有效性
        Integer orgId = item.getOrgId();
        Orgnization orgnization = (Orgnization)ics.getObjById(EIdType.orgId,orgId);

        // 檢查數(shù)據(jù)權(quán)限
        drs.checkUserDrByOrgId(request, orgId);

        // 檢查枚舉值
        int userType = item.getUserType().intValue();
        EUserType eUserType = EUserType.getTypeByCode(userType);
        int sex = item.getSex().intValue();
        ESex eSex = ESex.getTypeByCode(sex);

        // 檢查唯一性
        String userName = item.getUserName(); 
        String phoneNumber = item.getPhoneNumber(); 
        String idNo = item.getIdNo(); 
        String openId = item.getOpenId(); 
        String woaOpenid = item.getWoaOpenid(); 
        checkUniqueByUserName(userName);
        checkUniqueByPhoneNumber(phoneNumber);
        checkUniqueByIdNo(idNo);
        checkUniqueByOpenId(openId);
        checkUniqueByWoaOpenid(woaOpenid);
        
        // 業(yè)務(wù)處理
        LocalDateTime current = LocalDateTime.now();
        String salt = TimeUtil.format(current, "yyyy-MM-dd HH:mm:ss");
        // 明文密碼加密
        String password = item.getPassword();
        String encyptPassword = Md5Util.plaintPasswdToDbPasswd(password, salt, Constants.TOKEN_KEY);
        item.setSalt(salt);
        item.setPassword(encyptPassword);
        
        Long userId = 0L;
		// 獲取全局記錄ID
		Long globalRecId = tccs.getTableRecId("exa_users");
        userId = globalRecId;

		// 獲取操作人賬號(hào)
		String operatorName = getUserName(request);

		// 設(shè)置信息
		item.setUserId(userId);
		item.setOperatorName(operatorName);
		
		try {
    		// 插入數(shù)據(jù)
			userDao.insertItem(item);
			
		} catch(Exception e) {
			LogUtil.error(e);
			throw new BaseException(ExceptionCodes.ADD_OBJECT_FAILED,e.getMessage());
		}
		
		// 構(gòu)造返回值
		Map<String,Object> map = new HashMap<String,Object>();
        map.put("userId", userId.toString());
		
		return map;
	}

9.2.1、新增對(duì)象的參數(shù)校驗(yàn)

?	首先是參數(shù)校驗(yàn),使用checkValidForParams方法,此方法一般僅對(duì)輸入?yún)?shù)進(jìn)行值校驗(yàn),如字段是否缺失,值類(lèi)型是否匹配,數(shù)據(jù)格式是否正確等。
	/**
	 * @methodName			: checkValidForParams
	 * @description			: 輸入?yún)?shù)校驗(yàn)
	 * @param request		: request對(duì)象
	 * @param methodName	: 方法名稱(chēng)
	 * @param params		: 輸入?yún)?shù)
	 * @history				:
	 * ------------------------------------------------------------------------------
	 * date			version		modifier		remarks
	 * ------------------------------------------------------------------------------
	 * 2023/05/17	1.0.0		sheng.zheng		初版
	 *
	 */
	@Override
	public void checkValidForParams(HttpServletRequest request, String methodName, Object params) {
		switch(methodName) {
		case "addItem":
		{
			User item = (User)params;
			
			// 檢查項(xiàng): 必選字段
            ReflectUtil.checkMandatoryFields(item,mandatoryFieldList);

            // 用戶(hù)名格式校驗(yàn)
            ValidateUtil.loginNameValidator("userName", item.getUserName());
            
            // 手機(jī)號(hào)碼格式校驗(yàn)
            if (!item.getPhoneNumber().isEmpty()) {
            	ValidateUtil.phoneNumberValidator("phoneNumber", item.getPhoneNumber());
            }

            // email格式校驗(yàn)
            if (!item.getEmail().isEmpty()) {
                ValidateUtil.emailValidator("email", item.getEmail());            	
            } 			
		}
		break;
		// case "editItem":
		// ...
		default:
			break;
		}
	}
?	addItem方法的輸入?yún)?shù)校驗(yàn)。首先是必選字段校驗(yàn),檢查必選字段是否都有值。然后是相關(guān)屬性值的數(shù)據(jù)格式校驗(yàn)。
9.2.1.1、新增對(duì)象的必選字段校驗(yàn)
?	調(diào)用用ReflectUtil工具類(lèi)的checkMandatoryFields,檢查字符串類(lèi)型和整數(shù)的字段,是否有值。
	/**
	 * 
	 * @methodName		: checkMandatoryFields
	 * @description		: 檢查必選字段
	 * @param <T>		: 泛型類(lèi)型
	 * @param item		: T類(lèi)型對(duì)象
	 * @param mandatoryFieldList: 必選字段名數(shù)組
	 * @history		:
	 * ------------------------------------------------------------------------------
	 * date			version		modifier		remarks                   
	 * ------------------------------------------------------------------------------
	 * 2023/05/26	1.0.0		sheng.zheng		初版
	 *
	 */
	public static <T> void checkMandatoryFields(T item,String[] mandatoryFieldList) {
		// 獲取對(duì)象item的運(yùn)行時(shí)的類(lèi)
		Class<?> clazz = (Class<?>) item.getClass();
		String type = "";
		String shortType = "";	
		String error = "";
		for(String propName : mandatoryFieldList) {
			try {
	    		Field field = clazz.getDeclaredField(propName);
	    		field.setAccessible(true);	
				// 獲取字段類(lèi)型
				type = field.getType().getTypeName();
				// 獲取類(lèi)型的短名稱(chēng)
				shortType = getShortTypeName(type);
	    		
				// 獲取屬性值
				Object oVal = field.get(item);
				if (oVal == null) {
					// 如果必選字段值為null
					error += propName + ",";											
					continue;
				}
				switch(shortType) {
				case "Integer":
				case "int":
				{
					Integer iVal = Integer.valueOf(oVal.toString());
					if (iVal == 0) {
						// 整型類(lèi)型,有效值一般為非0
						error += propName + ",";
					}
				}
					break;
				case "String":
				{
					String sVal = oVal.toString();
					if (sVal.isEmpty()) {
						// 字符串類(lèi)型,有效值一般為非空串
						error += propName + ",";
					}
				}
					break;
				case "Byte":
				case "byte":
					// 字節(jié)類(lèi)型,一般用于枚舉值字段,后面使用枚舉值檢查,此處忽略
					break;	
				case "List":
				{
					List<?> list = (List<?>)oVal;
					if (list.size() == 0) {
						// 列表類(lèi)型,無(wú)成員
						error += propName + ",";
					}
				}
					break;
				default:
					break;
				}
			}catch(Exception e) {
				// 非屬性字段
				if (error.isEmpty()) {
					error += propName;											
				}else {
					error += "," + propName;
				}
			}
		}
		if (!error.isEmpty()) {
			error = Utility.trimLeftAndRight(error,"\\,");
			throw new BaseException(ExceptionCodes.ARGUMENTS_IS_EMPTY,error);
		}
	}
?	一般情況下,這個(gè)方法可以起作用。但特殊情況,如0值為有效值,-1為無(wú)效值,則會(huì)有誤報(bào)情況。此時(shí),可以使用另一個(gè)方法。
	/**
	 * 
	 * @methodName		: checkMandatoryFields
	 * @description		: 檢查必選字段
	 * @param <T>		: 泛型類(lèi)型
	 * @param item		: 參考對(duì)象,屬性字段值使用默認(rèn)值或區(qū)別于有效默認(rèn)值的無(wú)效值
	 * @param item2		: 被比較對(duì)象
	 * @param mandatoryFieldList: 必須字段屬性名列表
	 * @history		:
	 * ------------------------------------------------------------------------------
	 * date			version		modifier		remarks                   
	 * ------------------------------------------------------------------------------
	 * 2023/06/17	1.0.0		sheng.zheng		初版
	 *
	 */
	public static <T> void checkMandatoryFields(T item,T item2,
			String[] mandatoryFieldList) {
		Class<?> clazz = (Class<?>) item.getClass();
		String error = "";
		for(String propName : mandatoryFieldList) {
			try {
	    		Field field = clazz.getDeclaredField(propName);
	    		field.setAccessible(true);		    		
				// 獲取屬性值
				Object oVal = field.get(item);
	    		field.setAccessible(true);		    		
				// 獲取屬性值
				Object oVal2 = field.get(item2);
				if (oVal2 == null) {
					// 新值為null
					error += propName + ",";
					continue;
				}
				if (oVal != null) {
					if (oVal.equals(oVal2)) {
						// 如果值相等
						error += propName + ",";
					}
				}
				
			}catch(Exception e) {
				// 非屬性字段
				if (error.isEmpty()) {
					error += propName;											
				}else {
					error += "," + propName;
				}
			}
		}
		if (!error.isEmpty()) {
			error = Utility.trimLeftAndRight(error,"\\,");
			throw new BaseException(ExceptionCodes.ARGUMENTS_IS_EMPTY,error);
		}
	}
?	這個(gè)方法,增加了參考對(duì)象item,一般使用默認(rèn)值,新對(duì)象為item2,如果新對(duì)象的必選屬性值為參考對(duì)象一致,則認(rèn)為該屬性未賦值。這對(duì)于默認(rèn)值為有效值時(shí),會(huì)有問(wèn)題,此時(shí)調(diào)用方法前先將有效默認(rèn)值設(shè)置為無(wú)效值。
?	如User對(duì)象類(lèi),userType默認(rèn)值為3,是有效值??扇缦路椒ㄕ{(diào)用:
		User item = (User)params;

		// 檢查項(xiàng): 必選字段
		User refItem = new User();
		// 0為無(wú)效值
		refItem.setUserType((byte)0);			
        ReflectUtil.checkMandatoryFields(refItem,item,mandatoryFieldList);
?	使用ReflectUtil的mandatoryFieldList的方法,可以大大簡(jiǎn)化代碼。
9.2.1.2、數(shù)據(jù)格式校驗(yàn)
?	某些對(duì)象的某些屬性值,有數(shù)據(jù)格式要求,此時(shí)需要進(jìn)行數(shù)據(jù)格式校驗(yàn)。如用戶(hù)對(duì)象的用戶(hù)名(登錄名),手機(jī)號(hào)碼,email等。這些數(shù)據(jù)格式校驗(yàn),可以累計(jì)起來(lái),開(kāi)發(fā)工具方法,便于其它對(duì)象使用。
?	如下面是登錄名的格式校驗(yàn)方法,支持以字母開(kāi)頭,后續(xù)可以是字母、數(shù)字或"_.-@#%"特殊符號(hào),不支持中文。此校驗(yàn)方法沒(méi)有長(zhǎng)度校驗(yàn),由于各屬性的長(zhǎng)度要求不同,可以另行檢查。
	/**
	 * 
	 * @methodName		: checkLoginName
	 * @description		: 檢查登錄名格式是否正確,
	 * 	格式:字母開(kāi)頭,可以支持字母、數(shù)字、以及"_.-@#%"6個(gè)特殊符號(hào)
	 * @param loginName	: 登錄名
	 * @return		: 
	 * @history		:
	 * ------------------------------------------------------------------------------
	 * date			version		modifier		remarks                   
	 * ------------------------------------------------------------------------------
	 * 2023/06/16	1.0.0		sheng.zheng		初版
	 *
	 */
	public static boolean checkLoginName(String loginName) {
		String pattern = "^[a-zA-Z]([a-zA-Z0-9_.\\-@#%]*)$";
		boolean bRet = Pattern.matches(pattern,loginName);
		return bRet;
	}
	
	/**
	 * 
	 * @methodName		: loginNameValidator
	 * @description		: 登錄名稱(chēng)格式校驗(yàn),格式錯(cuò)誤拋出異常
	 * @param propName	: 登錄名稱(chēng)的提示名稱(chēng)
	 * @param loginName	: 登錄名稱(chēng)
	 * @history		:
	 * ------------------------------------------------------------------------------
	 * date			version		modifier		remarks                   
	 * ------------------------------------------------------------------------------
	 * 2023/06/16	1.0.0		sheng.zheng		初版
	 *
	 */
	public static void loginNameValidator(String propName,String loginName) {
		boolean bRet = checkLoginName(loginName);
		if (!bRet) {
			throw new BaseException(ExceptionCodes.DATA_FORMAT_WRONG, propName + ":" + loginName);
		}
	}
?	根據(jù)loginNameValidator核心是checkLoginName,但loginNameValidator方法針對(duì)錯(cuò)誤,直接拋出異常,調(diào)用時(shí)代碼可以更加簡(jiǎn)潔。類(lèi)似的思想,適用于數(shù)據(jù)權(quán)限檢查,參照ID檢查,枚舉值檢查,唯一鍵檢查等。
            // 用戶(hù)名格式校驗(yàn)
            ValidateUtil.loginNameValidator("userName", item.getUserName());
?	使用checkLoginName方法,則需要如下:
            // 用戶(hù)名格式校驗(yàn)
            if(!ValidateUtil.checkLoginName(item.getUserName())){
				throw new BaseException(ExceptionCodes.DATA_FORMAT_WRONG, "userName:" + item.getUserName());
			}

9.2.2、參照ID檢查

?	如果對(duì)象有外鍵,即參照對(duì)象,則外鍵(ID)必須有意義,即參照對(duì)象是存在的。
?	使用集中式的對(duì)象ID檢查服務(wù)類(lèi)IdCheckService,根據(jù)ID類(lèi)型和ID值,獲取對(duì)象。如果類(lèi)型指定的ID值對(duì)象不存在,則拋出異常。
        // 檢查參照ID的有效性
        Integer orgId = item.getOrgId();
        Orgnization orgnization = (Orgnization)ics.getObjById(EIdType.orgId,orgId);
?	至于IdCheckService中,根據(jù)ID獲取對(duì)象方法,可以直接查詢(xún)數(shù)據(jù)庫(kù),也可以通過(guò)緩存,這個(gè)取決于對(duì)象管理。

9.2.3、數(shù)據(jù)權(quán)限檢查

?	如果對(duì)象涉及數(shù)據(jù)權(quán)限,則需要檢查操作者是否有權(quán)新增此對(duì)象。
?	使用數(shù)據(jù)權(quán)限管理類(lèi)DataRightsService的方法,由于對(duì)一個(gè)確定的應(yīng)用,數(shù)據(jù)權(quán)限相關(guān)的字段個(gè)數(shù)是有限的,可以針對(duì)單個(gè)字段開(kāi)發(fā)接口,如orgId是數(shù)據(jù)權(quán)限字段,則可以提供checkUserDrByOrgId方法,代碼如下:
	/**
	 * 
	 * @methodName		: checkUserDrByOrgId
	 * @description		: 檢查當(dāng)前用戶(hù)是否對(duì)輸入的組織ID有數(shù)據(jù)權(quán)限
	 * @param request	: request對(duì)象
	 * @param orgId		: 組織ID
	 * @history		:
	 * ------------------------------------------------------------------------------
	 * date			version		modifier		remarks                   
	 * ------------------------------------------------------------------------------
	 * 2021/05/29	1.0.0		sheng.zheng		初版
	 *
	 */
	@SuppressWarnings("unchecked")
	@Override
	public void checkUserDrByOrgId(HttpServletRequest request,Integer orgId) {
		boolean bRights = false;
		
		// 獲取賬號(hào)緩存信息
		String accountId = accountCacheService.getId(request);
		// 獲取用戶(hù)類(lèi)型
		Integer userType = (Integer)accountCacheService.getAttribute(accountId,Constants.USER_TYPE);
		// 獲取數(shù)據(jù)權(quán)限緩存信息
		Map<String,UserDr> fieldDrMap = null;
		fieldDrMap = (Map<String,UserDr>)accountCacheService.getAttribute(accountId, Constants.DR_MAP);
		if (userType != null || fieldDrMap == null) {
			if (userType == EUserType.utAdminE.getCode()) {
				// 如果為系統(tǒng)管理員
				bRights = true;
				return;
			}
		}else {
			// 如果屬性不存在
			throw new BaseException(ExceptionCodes.TOKEN_EXPIRED);				
		}
				
		// 獲取數(shù)據(jù)權(quán)限
		UserDr userDr = null;
		bRights = true;
		List<UserCustomDr> userCustomDrList = null;
		String propName = "orgId";
			
		// 獲取用戶(hù)對(duì)此fieldId的權(quán)限
		userDr = fieldDrMap.get(propName);
		if (userDr.getDrType().intValue() == EDataRightsType.drtAllE.getCode()) {
			// 如果為全部,有權(quán)限
			return;
		}
		if (userDr.getDrType().intValue() == EDataRightsType.drtDefaultE.getCode()) {
			// 如果為默認(rèn)權(quán)限,進(jìn)一步檢查下級(jí)對(duì)象
			List<Integer> drList = getDefaultDrList(orgId,propName);
			boolean bFound = drList.contains(orgId);
			if (!bFound) {
				bRights = false;
			}
		}else if (userDr.getDrType().intValue() == EDataRightsType.drtCustomE.getCode()){
			// 如果為自定義數(shù)據(jù)權(quán)限
			List<Integer> orgIdList = null;
			if (userCustomDrList == null) {
				// 如果自定義列表為空,則獲取
				Long userId = (Long)accountCacheService.getAttribute(accountId,Constants.USER_ID);
				userCustomDrList = getUserCustomDrList(userId,propName);
				orgIdList = getUserCustomFieldList(userCustomDrList,propName);
				if (orgIdList != null) {
					boolean bFound = orgIdList.contains(orgId);
					if (!bFound) {
						bRights = false;
					}					
				}					
			}
		}			
		if (bRights == false) {
			throw new BaseException(ExceptionCodes.ACCESS_FORBIDDEN);
		}		
	}
?	當(dāng)前用戶(hù)的數(shù)據(jù)權(quán)限配置信息,使用key為屬性名的字典Map<String,UserDr>保存到各訪(fǎng)問(wèn)用戶(hù)的賬號(hào)緩存中。根據(jù)request對(duì)象,獲取當(dāng)前操作者的數(shù)據(jù)權(quán)限配置信息。然后根據(jù)配置類(lèi)型,檢查輸入權(quán)限值是否在用戶(hù)許可范圍內(nèi),如果不在,就拋出異常。

?	還可以提供更通用的單屬性數(shù)據(jù)權(quán)限檢查接口方法。
	/**
	 * 
	 * @methodName		: checkUserDrByDrId
	 * @description		: 檢查當(dāng)前用戶(hù)是否對(duì)指定權(quán)限字典的輸入值有數(shù)據(jù)權(quán)限
	 * @param request	: request對(duì)象
	 * @param propName	: 權(quán)限屬性名
	 * @param drId		: 權(quán)限屬性值
	 * @history		:
	 * ------------------------------------------------------------------------------
	 * date			version		modifier		remarks                   
	 * ------------------------------------------------------------------------------
	 * 2021/05/29	1.0.0		sheng.zheng		初版
	 *
	 */
	public void checkUserDrByDrId(HttpServletRequest request,String propName,Object drId); 	
?	多屬性數(shù)據(jù)權(quán)限檢查接口方法。
	/**
	 * 
	 * @methodName		: checkDataRights
	 * @description		: 檢查當(dāng)前用戶(hù)是否對(duì)給定對(duì)象有數(shù)據(jù)權(quán)限
	 * @param request	: request對(duì)象,可從中獲取當(dāng)前用戶(hù)的緩存信息
	 * @param params	: 權(quán)限屬性名與值的字典
	 * @history		:
	 * ------------------------------------------------------------------------------
	 * date			version		modifier		remarks                   
	 * ------------------------------------------------------------------------------
	 * 2021/03/13	1.0.0		sheng.zheng		初版
	 *
	 */
	public void checkUserDr(HttpServletRequest request,Map<String,Object> params); 	

9.2.4、枚舉值檢查

?	枚舉類(lèi)型,對(duì)應(yīng)的屬性數(shù)據(jù)類(lèi)型一般是Byte,數(shù)據(jù)庫(kù)使用tinyint。新增對(duì)象時(shí),枚舉字段的值要在枚舉類(lèi)型定義范圍中,否則會(huì)有問(wèn)題。
        // 檢查枚舉值
        int userType = item.getUserType().intValue();
        EUserType eUserType = EUserType.getTypeByCode(userType);
        int sex = item.getSex().intValue();
        ESex eSex = ESex.getTypeByCode(sex);	
?	相關(guān)枚舉類(lèi)型,都提供getTypeByCode方法,實(shí)現(xiàn)枚舉值有效性校驗(yàn)。如:
	/**
	 * 
	 * @methodName	: getType
	 * @description	: 根據(jù)code獲取枚舉值
	 * @param code	: code值 
	 * @return		: code對(duì)應(yīng)的枚舉值
	 * @history		:
	 * ------------------------------------------------------------------------------
	 * date			version		modifier		remarks                   
	 * ------------------------------------------------------------------------------
	 * 2023/05/17	1.0.0		sheng.zheng		初版
	 *
	 */
	public static EUserType getType(int code) {
		// 返回值變量
		EUserType eRet = null;
		
		for (EUserType item : values()) {
			// 遍歷每個(gè)枚舉值
			if (code == item.getCode()) {
				// code匹配
				eRet = item;
				break;
			}
		}
		
		return eRet;
	}

	// 檢查并獲取指定code的枚舉值
	public static EUserType getTypeByCode(int code) {
		EUserType item = getType(code);
		if (item == null) {
			throw new BaseException(ExceptionCodes.INVALID_ENUM_VALUE,"EUserType with code="+code);
		}
		
		return item;
	}

9.2.5、唯一性檢查

?	如果對(duì)象屬性值有唯一性要求,則需要進(jìn)行唯一性檢查。
        // 檢查唯一性
        String userName = item.getUserName(); 
        String phoneNumber = item.getPhoneNumber(); 
        String idNo = item.getIdNo(); 
        String openId = item.getOpenId(); 
        String woaOpenid = item.getWoaOpenid(); 
        checkUniqueByUserName(userName);
        checkUniqueByPhoneNumber(phoneNumber);
        checkUniqueByIdNo(idNo);
        checkUniqueByOpenId(openId);
        checkUniqueByWoaOpenid(woaOpenid);	
?	相關(guān)唯一性檢查方法,如下(也可以改為public以對(duì)外提供服務(wù)):
	/**
	 * 
	 * @methodName		: checkUniqueByUserName
	 * @description	    : 檢查userName屬性值的唯一性
     * @param userName	: 用戶(hù)名
	 * @history		    : 
	 * ------------------------------------------------------------------------------
	 * date			version		modifier		remarks                   
	 * ------------------------------------------------------------------------------
	 * 2023/05/17	1.0.0		sheng.zheng		初版
	 *
	 */
    private void checkUniqueByUserName(String userName) {
        User item = userDao.selectItemByUserName(userName);
        if (item != null) {
            // 如果唯一鍵對(duì)象已存在
            throw new BaseException(ExceptionCodes.OBJECT_ALREADY_EXISTS,"userName=" + userName);            
        }
    }

	/**
	 * 
	 * @methodName		: checkUniqueByPhoneNumber
	 * @description	    : 檢查phoneNumber屬性值的唯一性
     * @param phoneNumber	: 手機(jī)號(hào)碼
	 * @history		    : 
	 * ------------------------------------------------------------------------------
	 * date			version		modifier		remarks                   
	 * ------------------------------------------------------------------------------
	 * 2023/05/17	1.0.0		sheng.zheng		初版
	 *
	 */
    private void checkUniqueByPhoneNumber(String phoneNumber) {
        if (phoneNumber.equals("")) {
            // 如果為例外值
            return;
        }

        User item = userDao.selectItemByPhoneNumber(phoneNumber);
        if (item != null) {
            // 如果唯一鍵對(duì)象已存在
            throw new BaseException(ExceptionCodes.OBJECT_ALREADY_EXISTS,
            	"phoneNumber=" + phoneNumber);            
        }
    }

	/**
	 * 
	 * @methodName		: checkUniqueByIdNo
	 * @description	    : 檢查idNo屬性值的唯一性
     * @param idNo		: 身份證號(hào)碼
	 * @history		    : 
	 * ------------------------------------------------------------------------------
	 * date			version		modifier		remarks                   
	 * ------------------------------------------------------------------------------
	 * 2023/05/17	1.0.0		sheng.zheng		初版
	 *
	 */
    private void checkUniqueByIdNo(String idNo) {
        if (idNo.equals("")) {
            // 如果為例外值
            return;
        }

        User item = userDao.selectItemByIdNo(idNo);
        if (item != null) {
            // 如果唯一鍵對(duì)象已存在
            throw new BaseException(ExceptionCodes.OBJECT_ALREADY_EXISTS,"idNo=" + idNo);            
        }
    }

	/**
	 * 
	 * @methodName		: checkUniqueByOpenId
	 * @description	    : 檢查openId屬性值的唯一性
     * @param openId	: 微信小程序的openid
	 * @history		    : 
	 * ------------------------------------------------------------------------------
	 * date			version		modifier		remarks                   
	 * ------------------------------------------------------------------------------
	 * 2023/05/17	1.0.0		sheng.zheng		初版
	 *
	 */
    private void checkUniqueByOpenId(String openId) {
        if (openId.equals("")) {
            // 如果為例外值
            return;
        }

        User item = userDao.selectItemByOpenId(openId);
        if (item != null) {
            // 如果唯一鍵對(duì)象已存在
            throw new BaseException(ExceptionCodes.OBJECT_ALREADY_EXISTS,"openId=" + openId);            
        }
    }

	/**
	 * 
	 * @methodName		: checkUniqueByWoaOpenid
	 * @description	    : 檢查woaOpenid屬性值的唯一性
     * @param woaOpenid	: 微信公眾號(hào)openid
	 * @history		    : 
	 * ------------------------------------------------------------------------------
	 * date			version		modifier		remarks                   
	 * ------------------------------------------------------------------------------
	 * 2023/05/17	1.0.0		sheng.zheng		初版
	 *
	 */
    private void checkUniqueByWoaOpenid(String woaOpenid) {
        if (woaOpenid.equals("")) {
            // 如果為例外值
            return;
        }

        User item = userDao.selectItemByWoaOpenid(woaOpenid);
        if (item != null) {
            // 如果唯一鍵對(duì)象已存在
            throw new BaseException(ExceptionCodes.OBJECT_ALREADY_EXISTS,"woaOpenid=" + woaOpenid);            
        }
    }

9.2.6、業(yè)務(wù)處理

?	如果新增對(duì)象時(shí),需要一些內(nèi)部處理,則在此處進(jìn)行。如新增用戶(hù)時(shí),需要根據(jù)當(dāng)前時(shí)間生成鹽,然后將管理員輸入的明文密碼轉(zhuǎn)為加鹽Md5簽名密碼。
        // 業(yè)務(wù)處理
        LocalDateTime current = LocalDateTime.now();
        String salt = TimeUtil.format(current, "yyyy-MM-dd HH:mm:ss");
        // 明文密碼加密
        String password = item.getPassword();
        String encyptPassword = Md5Util.plaintPasswdToDbPasswd(password, salt, Constants.TOKEN_KEY);
        item.setSalt(salt);
        item.setPassword(encyptPassword); 

9.2.7、獲取全局ID

?	為當(dāng)前對(duì)象分配全局ID。
        Long userId = 0L;
		// 獲取全局記錄ID
		Long globalRecId = tccs.getTableRecId("exa_users");
        userId = globalRecId;
?	全局ID的獲取使用全局ID服務(wù)類(lèi)對(duì)象TableCodeConfigService,其提供單個(gè)ID和批量ID的獲取接口。
	/**
	 * 
	 * @methodName		: getTableRecId
	 * @description		: 獲取指定表名的一條記錄ID
	 * @param tableName	: 表名
	 * @return			: 記錄ID
	 * @history		:
	 * ------------------------------------------------------------------------------
	 * date			version		modifier		remarks                   
	 * ------------------------------------------------------------------------------
	 * 2021/01/01	1.0.0		sheng.zheng		初版
	 *
	 */
	@Override
	public Long getTableRecId(String tableName) {
		int tableId = getTableId(tableName);
		Long recId = getGlobalIdDao.getTableRecId(tableId);
		return recId;
	}
	
	/**
	 * 
	 * @methodName		: getTableRecIds
	 * @description		: 獲取指定表名的多條記錄ID
	 * @param tableName	: 表名
	 * @param recCount	: 記錄條數(shù)
	 * @return			: 第一條記錄ID
	 * @history		:
	 * ------------------------------------------------------------------------------
	 * date			version		modifier		remarks                   
	 * ------------------------------------------------------------------------------
	 * 2021/01/01	1.0.0		sheng.zheng		初版
	 *
	 */
	@Override
	public Long getTableRecIds(String tableName,int recCount) {
		int tableId = getTableId(tableName);
		Long recId = getGlobalIdDao.getTableRecIds(tableId,recCount);
		return recId;		
	}
?	getTableId是根據(jù)數(shù)據(jù)表名稱(chēng),獲取表ID(這些表是相對(duì)固定的,可以使用緩存字典來(lái)管理)。而getGlobalIdDao的方法就是調(diào)用數(shù)據(jù)庫(kù)的函數(shù)exa_get_global_id,獲取可用ID。
	/**
	 * 
	 * @methodName		: getTableRecId
	 * @description		: 獲取表ID的一個(gè)記錄ID
	 * @param tableId	: 表ID
	 * @return			: 記錄ID
	 * @history		:
	 * ------------------------------------------------------------------------------
	 * date			version		modifier		remarks                   
	 * ------------------------------------------------------------------------------
	 * 2021/01/01	1.0.0		sheng.zheng		初版
	 *
	 */
	@Select("SELECT exa_get_global_id(#{tableId}, 1)")
	Long getTableRecId(@Param("tableId") Integer tableId);
	
	/**
	 * 
	 * @methodName		: getTableRecIds
	 * @description		: 獲取表ID的多個(gè)記錄ID
	 * @param tableId	: 表ID
	 * @param count		: ID個(gè)數(shù)
	 * @return			: 開(kāi)始的記錄ID
	 * @history		:
	 * ------------------------------------------------------------------------------
	 * date			version		modifier		remarks                   
	 * ------------------------------------------------------------------------------
	 * 2021/01/01	1.0.0		sheng.zheng		初版
	 *
	 */
	@Select("SELECT exa_get_global_id(#{tableId}, #{count})")
	Long getTableRecIds(@Param("tableId") Integer tableId, @Param("count") Integer count);

9.2.8、設(shè)置記錄的用戶(hù)賬號(hào)信息

?	從request對(duì)象中獲取賬號(hào)信息,并設(shè)置對(duì)象。
		// 獲取操作人賬號(hào)
		String operatorName = getUserName(request);

		// 設(shè)置信息
		item.setUserId(userId);
		item.setOperatorName(operatorName);

9.2.9、新增記錄

?	調(diào)用Dao的insertItem方法,新增記錄。
		try {
    		// 插入數(shù)據(jù)
			userDao.insertItem(item);
			
		} catch(Exception e) {
			LogUtil.error(e);
			throw new BaseException(ExceptionCodes.ADD_OBJECT_FAILED,e.getMessage());
		}

9.2.10、緩存處理

?	新增用戶(hù)對(duì)象,不涉及緩存處理。
?	如果有的對(duì)象,涉及全集加載,如組織樹(shù),則新增對(duì)象時(shí),組織樹(shù)也會(huì)變化。為了避免無(wú)效加載,使用修改標(biāo)記來(lái)表示集合被修改,獲取全集時(shí),再進(jìn)行加載。這樣,連續(xù)新增對(duì)象時(shí),不會(huì)有無(wú)效加載。緩存涉及全集加載的,新增對(duì)象需設(shè)置修改標(biāo)記。
?	如果緩存不涉及全集的,則無(wú)需處理。如字典類(lèi)緩存,新增時(shí)不必將新對(duì)象加入緩存,獲取時(shí),根據(jù)機(jī)制,緩存中不存在,會(huì)先請(qǐng)求數(shù)據(jù)庫(kù),此時(shí)可以加載到緩存中。

9.2.11、返回值處理

?	新增對(duì)象,如果是系統(tǒng)生成的ID,需要將ID值返回。
		// 構(gòu)造返回值
		Map<String,Object> map = new HashMap<String,Object>();
        map.put("userId", userId.toString());
		
		return map;
?	對(duì)于Long類(lèi)型,由于前端可能損失精度,因此使用字符串類(lèi)型傳遞。

(未完待續(xù)...)文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-487318.html

到了這里,關(guān)于Spring Boot實(shí)現(xiàn)高質(zhì)量的CRUD-5的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來(lái)自互聯(lián)網(wǎng)用戶(hù)投稿,該文觀(guān)點(diǎn)僅代表作者本人,不代表本站立場(chǎng)。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • AI Code Translator —— 能夠?qū)崿F(xiàn)高質(zhì)量的自動(dòng)編程語(yǔ)言轉(zhuǎn)換工具

    AI Code Translator —— 能夠?qū)崿F(xiàn)高質(zhì)量的自動(dòng)編程語(yǔ)言轉(zhuǎn)換工具

    https://github.com/mckaywrigley/ai-code-translator AI Code Translator —— 是一款基于大型語(yǔ)言模型的代碼翻譯工具,同時(shí)也是一款顛覆性的編程語(yǔ)言翻譯工具,它基于先進(jìn)的機(jī)器學(xué)習(xí)技術(shù)和大規(guī)模語(yǔ)料庫(kù)訓(xùn)練而成,能夠?qū)崿F(xiàn)高質(zhì)量的自動(dòng)編程語(yǔ)言轉(zhuǎn)換。 這款工具最大的突破在于翻譯速度快且

    2024年02月04日
    瀏覽(64)
  • 如何編寫(xiě)高質(zhì)量代碼

    如何編寫(xiě)高質(zhì)量代碼

    現(xiàn)代軟件開(kāi)發(fā)中,代碼是構(gòu)建高質(zhì)量軟件的核心。高質(zhì)量代碼能夠提高軟件系統(tǒng)的可靠性、可維護(hù)性和可擴(kuò)展性,減少bug的數(shù)量和修復(fù)時(shí)間,提升開(kāi)發(fā)效率和代碼可讀性,同時(shí)有助于團(tuán)隊(duì)協(xié)作和知識(shí)傳承共享。 然而,夢(mèng)想是豐滿(mǎn)的,現(xiàn)實(shí)是骨感的!軟件開(kāi)發(fā)面臨諸多挑戰(zhàn)。

    2024年02月02日
    瀏覽(675)
  • 高質(zhì)量橢圓檢測(cè)庫(kù)

    高質(zhì)量橢圓檢測(cè)庫(kù)

    目錄 前言 效果展示 檢測(cè)庫(kù) 簡(jiǎn)介 安裝庫(kù) 用法 測(cè)試 論文算法步驟簡(jiǎn)讀 1. lsd 檢測(cè) 2. lsd group 3. 生成初始 ellipse 4. 聚類(lèi) 橢圓檢測(cè)是工業(yè)中比較常用的一種檢測(cè)需求。目前常用的基于傳統(tǒng)圖像處理的橢圓檢測(cè)方法是霍夫變換,但是霍變換的檢測(cè)率比較低,很難滿(mǎn)足工業(yè)場(chǎng)景。而基

    2024年02月07日
    瀏覽(876)
  • 如何寫(xiě)出高質(zhì)量代碼?

    作為一名資深開(kāi)發(fā)人員,寫(xiě)出高質(zhì)量的代碼是我們必須要追求的目標(biāo)。然而,在實(shí)際開(kāi)發(fā)中,我們常常會(huì)遇到各種問(wèn)題。比如,代碼的可讀性、可維護(hù)性、健壯性和靈活性等,這些都會(huì)影響代碼的質(zhì)量。那么,究竟如何才能寫(xiě)出高質(zhì)量的代碼呢? 代碼結(jié)構(gòu)清晰易懂,能夠使代

    2024年02月02日
    瀏覽(104)
  • 如何寫(xiě)出高質(zhì)量代碼

    一、 前言 編寫(xiě)高質(zhì)量代碼是每一位程序員的追求。高質(zhì)量的代碼可以提高代碼可讀性、可維護(hù)性、可擴(kuò)展性以及軟件運(yùn)行的性能和穩(wěn)定性。在這篇文章中,我將分享一些編寫(xiě)高質(zhì)量代碼的特征、編程實(shí)踐技巧和軟件工程方法論。 可讀性:好的代碼應(yīng)該能夠被維護(hù)者輕易地理

    2024年02月02日
    瀏覽(111)
  • 如何寫(xiě)出高質(zhì)量的代碼

    你是否曾經(jīng)為自己寫(xiě)的代碼而感到懊惱?你是否想過(guò)如何才能寫(xiě)出高質(zhì)量代碼?那就不要錯(cuò)過(guò)這個(gè)話(huà)題!在這里,我們可以討論什么是高質(zhì)量代碼,如何寫(xiě)出高質(zhì)量代碼等問(wèn)題。無(wú)論你是初學(xué)者還是資深開(kāi)發(fā)人員,都可以在這個(gè)話(huà)題下進(jìn)行分享,汲取靈感和知識(shí),共同提高自

    2023年04月25日
    瀏覽(100)
  • 網(wǎng)絡(luò)安全高質(zhì)量文庫(kù)

    網(wǎng)絡(luò)安全高質(zhì)量文庫(kù)

    PeiQI文庫(kù) http://api.orchidstudio.cn/ PeiQi文庫(kù)是一個(gè)面對(duì)網(wǎng)絡(luò)安全從業(yè)者的知識(shí)庫(kù),涉及漏洞研究,代碼審計(jì),CTF奪旗,紅藍(lán)對(duì)抗等多個(gè)安全方向,用于解決安全信息不聚合,安全資料不易找的難題。幫助網(wǎng)絡(luò)安全從業(yè)者共同構(gòu)建安全的互聯(lián)網(wǎng),快速驗(yàn)證并及時(shí)修復(fù)相關(guān)漏洞,為甲

    2024年02月12日
    瀏覽(96)
  • 有哪些高質(zhì)量的自學(xué)網(wǎng)站?

    有哪些高質(zhì)量的自學(xué)網(wǎng)站?

    分享32個(gè)鮮為人知并且完全免費(fèi)的高質(zhì)量自學(xué)網(wǎng)站,每個(gè)都是堪稱(chēng)神器,讓你相見(jiàn)恨晚。 是一個(gè)完全免費(fèi)的綜合視頻教程網(wǎng)站,非常良心實(shí)用。 它提供的視頻教程非常豐富并且質(zhì)量很高,包括:PS 教程、手機(jī)攝影教程、Ai 做圖教程、Excel 教程、Word 教程、PPT 教程、Pr 視頻剪輯

    2024年02月02日
    瀏覽(96)
  • 如何編寫(xiě)高質(zhì)量的測(cè)試計(jì)劃

    如何編寫(xiě)高質(zhì)量的測(cè)試計(jì)劃

    1.1目的 簡(jiǎn)述本計(jì)劃的目的,旨在說(shuō)明各種測(cè)試階段任務(wù)、人員分配和時(shí)間安排、工作規(guī)范等。 測(cè)試計(jì)劃在策略和方法的高度說(shuō)明如何計(jì)劃、組織和管理測(cè)試項(xiàng)目。測(cè)試計(jì)劃包含足夠的信息使測(cè)試人員明白項(xiàng)目需要做什么是如何運(yùn)作的。另外,清晰的文檔結(jié)構(gòu)能使任何一個(gè)讀

    2024年02月16日
    瀏覽(93)
  • Visio 轉(zhuǎn)為高質(zhì)量PDF

    Visio 轉(zhuǎn)為高質(zhì)量PDF

    Visio另存為pdf不夠清晰怎么辦 - - 可以選擇先另存為高分辨率的圖片( 存的時(shí)候分辨率選擇打印機(jī)或者自定義即可 ),然后轉(zhuǎn)為pdf. 或者用 打印 1 保存為高質(zhì)量 2 的pdf (本文介紹) 版本:Microsoft Visio 2010 Adobe Acrobat 2018 關(guān)鍵就是設(shè)置分辨率,不按照以上流程亦可 一般情況下安裝完

    2024年02月04日
    瀏覽(209)

覺(jué)得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包