您好,登錄后才能下訂單哦!
Service如何實(shí)現(xiàn)&Zuul配置&Test,相信很多沒(méi)有經(jīng)驗(yàn)的人對(duì)此束手無(wú)策,為此本文總結(jié)了問(wèn)題出現(xiàn)的原因和解決方法,通過(guò)這篇文章希望你能解決這個(gè)問(wèn)題。
這里我們使用Spring DATA JPA
來(lái)實(shí)現(xiàn)數(shù)據(jù)庫(kù)操作,當(dāng)然大家也可以使用Mybatis
,都是一樣的,我們依然以用戶表操作為例:
/** * AdUserRepository for 用戶數(shù)據(jù)庫(kù)操作接口 * 繼承自JpaRepository<AdUser, Long>,第一個(gè)參數(shù)AdUser代表當(dāng)前要操作的實(shí)體類的class定義,第二個(gè)參數(shù)Long表示該類的主鍵類型 * * @author <a href="mailto:magicianisaac@gmail.com">Isaac.Zhang</a> */ public interface AdUserRepository extends JpaRepository<AdUser, Long> { /** * 根據(jù)用戶名稱獲取用戶 * * @param username 名稱 * @return 用戶對(duì)象 */ AdUser findByUserName(String username); List<AdUser> findAllByUserName(String userName); }
JPARepository 的默認(rèn)實(shí)現(xiàn)方法,如果我們只是繼承了JpaRepository
而沒(méi)有實(shí)現(xiàn)具體的操作方法,我們也是可以通過(guò)使用它的默認(rèn)方法來(lái)做CRUD
操作的,如下:
創(chuàng)建service package,依然以用戶操作為例,創(chuàng)建com.sxzhongf.ad.service.IUserService
和com.sxzhongf.ad.service.impl.UserServiceImpl
,UserServiceImpl
實(shí)現(xiàn)了IUserService
。
創(chuàng)建 IUserService
接口
/** * IUserService for 用戶service * * @author <a href="mailto:magicianisaac@gmail.com">Isaac.Zhang | 若初</a> */ public interface IUserService { /** * 創(chuàng)建用戶接口 * * @param userRequestVO {@link UserRequestVO} * @return {@link UserResponseVO} * @throws AdException 錯(cuò)誤 */ UserResponseVO createUser(UserRequestVO userRequestVO) throws AdException; List<AdUser> findAllByUserName(String userName); }
使用IUserService
接口
/** * UserServiceImpl for 用戶service * * @author <a href="mailto:magicianisaac@gmail.com">Isaac.Zhang | 若初</a> */ @Slf4j @Service public class UserServiceImpl implements IUserService { private final AdUserRepository userRepository; @Autowired public UserServiceImpl(AdUserRepository userRepository) { this.userRepository = userRepository; } /** * 創(chuàng)建用戶 * * @param userRequestVO {@link UserRequestVO} * @return result {@link UserResponseVO} */ @Override @Transactional public UserResponseVO createUser(UserRequestVO userRequestVO) throws AdException { if (!userRequestVO.validate()) { log.error("Request params error: {}", userRequestVO); throw new AdException(Constants.ErrorMessage.REQUEST_PARAM_ERROR); } //查重 AdUser existUser = userRepository.findByUserName(userRequestVO.getUserName()); if (existUser != null) { log.error("{} user is not exist.", userRequestVO.getUserName()); throw new AdException(Constants.ErrorMessage.USER_EXIST); } AdUser user = userRepository.save(new AdUser(userRequestVO.getUserName(), CommonUtils.md5(userRequestVO.getUserName()))); log.info("current user is : {}", user); return new UserResponseVO(user.getUserId(), user.getUserName(), user.getToken(), user.getCreateTime(), user.getUpdateTime()); } @Override public List<AdUser> findAllByUserName(String userName) { return userRepository.findAllByUserName(userName); } }
創(chuàng)建數(shù)據(jù)傳輸對(duì)象(dto/vo)
其實(shí)好多人在這里都會(huì)特別郁悶,搞不清楚這些命名有什么區(qū)別,個(gè)人建議是大家不用糾結(jié),dto(data transfer object),就是表示我們?cè)诟鱾€(gè)層傳遞的對(duì)象,vo在展示層操作的對(duì)象。但是這個(gè)只是個(gè)命名,它的本質(zhì)就是一個(gè)object, 你傳遞到DAO層可以嗎?當(dāng)然可以,你傳單獨(dú)字段都是可以的。所以,沒(méi)必要過(guò)分糾結(jié)這種信息,咬文嚼字有時(shí)候反而會(huì)適得其反。
/** * UserRequestVO for 創(chuàng)建用戶請(qǐng)求對(duì)象VO * * @author <a href="mailto:magicianisaac@gmail.com">Isaac.Zhang | 若初</a> */ @Data @AllArgsConstructor @NoArgsConstructor public class UserRequestVO { private String userName; public boolean validate() { return !StringUtils.isEmpty(userName); } } --- /** * UserResponseVO for 用戶響應(yīng)VO * * @author <a href="mailto:magicianisaac@gmail.com">Isaac.Zhang | 若初</a> */ @Data @AllArgsConstructor @NoArgsConstructor public class UserResponseVO { private Long userId; private String userName; private String token; private Date createTime; private Date updateTime; }
因?yàn)閳?bào)錯(cuò)信息有可能是相同的,那我們抽取一個(gè)常量類來(lái)封裝。
/** * Constants for TODO * * @author <a href="mailto:magicianisaac@gmail.com">Isaac.Zhang | 若初</a> */ public class Constants { /** * 通用錯(cuò)誤信息異常類 */ public static class ErrorMessage { public static final String REQUEST_PARAM_ERROR = "請(qǐng)求參數(shù)異常"; public static final String USER_EXIST = "用戶已存在"; public static final String USER_NOT_EXIST = "用戶不存在"; } }
在Common Project 下面創(chuàng)建一個(gè)工具類com.sxzhongf.ad.common.utils.CommonUtils
,用來(lái)對(duì)用戶username進(jìn)行md5加密來(lái)獲取token信息。
/** * CommonUtils for 工具類 * * @author <a href="mailto:magicianisaac@gmail.com">Isaac.Zhang | 若初</a> */ @Slf4j public class CommonUtils { /** * md5 加密 */ public static String md5(String value) { return DigestUtils.md5Hex(value).toUpperCase(); } }
參考創(chuàng)建用戶的實(shí)現(xiàn),依次實(shí)現(xiàn)其他表操作。
依然以用戶功能實(shí)現(xiàn)為例:
/** * UserController for 用戶controller * * @author <a href="mailto:magicianisaac@gmail.com">Isaac.Zhang | 若初</a> */ @RestController @Slf4j @RequestMapping("/user") public class UserController { @Autowired private IUserService userService; @PostMapping(path = "/create") public UserResponseVO createUser(@RequestBody UserRequestVO requestVO) throws AdException { log.info("ad-sponsor: createUser -> {}", JSON.toJSONString(requestVO)); return userService.createUser(requestVO); } @GetMapping(path = "/get") public CommonResponse getUserList(@Param(value = "username") String username) throws AdException { log.info("ad-sponsor: getUserList -> {}", JSON.toJSONString(username)); return new CommonResponse(userService.findAllByUserName(username)); } }
我們?cè)谕斗畔到y(tǒng)的配置中,配置了server.servlet.context-path:/ad-sponsor
這么一個(gè)路徑,意味著所有請(qǐng)求當(dāng)前系統(tǒng)的路徑都需要帶有ad-sponsor, 例如:http://xxx/ad-sponsor/user/get?username=yyy
,這是網(wǎng)關(guān)請(qǐng)求所必需的。根據(jù)上述,我們?cè)诰W(wǎng)關(guān)服務(wù)中配置我們當(dāng)前的投放系統(tǒng):
spring: application: name: ad-gateway-zuul server: port: 1111 eureka: client: service-url: defaultZone: http://server1:7777/eureka/,http://server2:8888/eureka/,http://server3:9999/eureka/ instance: hostname: ad-gateway-zuul ############################################## # 以下為重要信息 zuul: ignored-services: '*' # 過(guò)濾所有請(qǐng)求,除了下面routes中聲明過(guò)的服務(wù) # 配置網(wǎng)關(guān)路由規(guī)則 routes: sponsor: #在路由中自定義服務(wù)路由名稱 path: /ad-sponsor/** serviceId: mscx-ad-sponsor #微服務(wù)name strip-prefix: false search: #在路由中自定義服務(wù)路由名稱 path: /ad-search/** serviceId: mscx-ad-search #微服務(wù)name strip-prefix: false prefix: /gateway/api strip-prefix: false #不對(duì) prefix: /gateway/api 設(shè)置的路徑進(jìn)行截取,默認(rèn)轉(zhuǎn)發(fā)會(huì)截取掉配置的前綴
直接訪問(wèn)投放系統(tǒng)
調(diào)用curl -G http://localhost:7000/ad-sponsor/user/get?username=Isaac%20Zhang
,返回結(jié)果:
{ code: 0, // 統(tǒng)一成功標(biāo)示 message: "success", // 統(tǒng)一處理結(jié)果message data: [ // 具體的對(duì)象信息 { userId: 10, userName: "Isaac Zhang", token: "2D3ABB6F2434109A105170FB21D00453", userStatus: 1, createTime: 1561118873000, updateTime: 1561118873000 } ] }
通過(guò)網(wǎng)關(guān)調(diào)用
因?yàn)槲以诰W(wǎng)關(guān)配置中加了前綴prefix: /gateway/api
,因此,我們?cè)L問(wèn)的時(shí)候需要添加上這個(gè)前綴信息,否則會(huì)報(bào)404錯(cuò)誤。
curl -G http://localhost:1111/gateway/api/ad-sponsor/user/get?username=Isaac%20Zhang
,我們發(fā)現(xiàn)結(jié)果并沒(méi)有按照我們想象的展示出來(lái)。
bogon:~ zhangpan$ http://localhost:1111/gateway/api/ad-sponsor/user/get?username=Isaac%20Zhang -bash: http://localhost:1111/gateway/api/ad-sponsor/user/get?username=Isaac%20Zhang: No such file or directory
為什么呢?我們來(lái)查看一下日志:
2019-07-27 20:44:19.093 INFO 4766 --- [nio-1111-exec-4] c.s.a.g.filter.ValidateTokenFilter : GET request to http://localhost:1111/gateway/api/ad-sponsor/user/get 2019-07-27 20:44:19.093 WARN 4766 --- [nio-1111-exec-4] c.s.a.g.filter.ValidateTokenFilter : access token is empty 2019-07-27 20:44:19.098 INFO 4766 --- [nio-1111-exec-4] c.s.ad.gateway.filter.AccessLogFilter : Request "/gateway/api/ad-sponsor/user/get" spent : 0 seconds. 2019-07-27 20:48:37.801 INFO 4766 --- [trap-executor-0] c.n.d.s.r.aws.ConfigClusterResolver : Resolving eureka endpoints via configuration
我們可以清晰的看到,ValidateTokenFilter : access token is empty
,為什么會(huì)有這么一個(gè)報(bào)錯(cuò)呢?那是因?yàn)槲以谂渲镁W(wǎng)關(guān)的時(shí)候,添加了一次攔截:
/** * ValidateTokenFilter for 服務(wù)token校驗(yàn) * * @author <a href="mailto:magicianisaac@gmail.com">Isaac.Zhang</a> */ @Slf4j @Component public class ValidateTokenFilter extends ZuulFilter { ... @Override public Object run() throws ZuulException { RequestContext ctx = RequestContext.getCurrentContext(); HttpServletRequest request = ctx.getRequest(); log.info(String.format("%s request to %s", request.getMethod(), request.getRequestURL().toString())); Object accessToken = request.getHeader("accessToken"); //.getParameter("accessToken"); if (accessToken == null) { log.warn("access token is empty"); ctx.setSendZuulResponse(false); ctx.setResponseStatusCode(401); // ctx.setResponseBody(body)對(duì)返回body內(nèi)容進(jìn)行編輯 return null; } log.info("access token ok"); return null; } }
觀察代碼我們發(fā)現(xiàn),會(huì)從RequestHeader
中獲取accessToken
參數(shù),我們沒(méi)有提供,當(dāng)然就會(huì)報(bào)錯(cuò)了呀。接下來(lái),我們提供上該參數(shù)再試:
bogon:~ zhangpan$ curl -H "accessToken:true" http://localhost:1111/gateway/api/ad-sponsor/user/get?username=Isaac%20Zhang ---返回 {"code":0,"message":"success","data":[{"userId":10,"userName":"Isaac Zhang","token":"2D3ABB6F2434109A105170FB21D00453","userStatus":1,"createTime":1561118873000,"updateTime":1561118873000}]}
至此,我們的廣告投放系統(tǒng)簡(jiǎn)單功能已經(jīng)全部實(shí)現(xiàn)完畢,并且可以通過(guò)網(wǎng)關(guān)進(jìn)行轉(zhuǎn)發(fā)。
看完上述內(nèi)容,你們掌握Service如何實(shí)現(xiàn)&Zuul配置&Test的方法了嗎?如果還想學(xué)到更多技能或想了解更多相關(guān)內(nèi)容,歡迎關(guān)注億速云行業(yè)資訊頻道,感謝各位的閱讀!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。