最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

SpringMVC對(duì)自定義controller入?yún)㈩A(yù)處理方式

 更新時(shí)間:2021年09月14日 11:03:11   作者:xdoyf  
這篇文章主要介紹了SpringMVC對(duì)自定義controller入?yún)㈩A(yù)處理方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教

Spring Mvc對(duì)自定義controller入?yún)㈩A(yù)處理

在初學(xué)springmvc框架時(shí),我就一直有一個(gè)疑問,為什么controller方法上竟然可以放這么多的參數(shù),而且都能得到想要的對(duì)象,比如HttpServletRequest或HttpServletResponse,各種注解@RequestParam、@RequestHeader、@RequestBody、@PathVariable、@ModelAttribute等。相信很多初學(xué)者都曾經(jīng)感慨過。

這篇文章就是講解處理這方面內(nèi)容的

我們可以模仿springmvc的源碼,實(shí)現(xiàn)一些我們自己的實(shí)現(xiàn)類,而方便我們的代碼開發(fā)。

HandlerMethodArgumentResolver接口說明

package org.springframework.web.method.support;
import org.springframework.core.MethodParameter;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
public interface HandlerMethodArgumentResolver {
    //用于判定是否需要處理該參數(shù)分解,返回true為需要,并會(huì)去調(diào)用下面的方法resolveArgument。
    boolean supportsParameter(MethodParameter parameter);
    //真正用于處理參數(shù)分解的方法,返回的Object就是controller方法上的形參對(duì)象。
    Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
            NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception;
}

示例

本示例顯示如何 優(yōu)雅地將傳入的信息轉(zhuǎn)化成自定義的實(shí)體傳入controller方法。

post 數(shù)據(jù):

first_name = Bill

last_name = Gates

初學(xué)者一般喜歡類似下面的代碼

package com.demo.controller;
import javax.servlet.http.HttpServletRequest;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import com.demo.domain.Person;
import com.demo.mvc.annotation.MultiPerson;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@Controller
@RequestMapping("demo1")
public class HandlerMethodArgumentResolverDemoController {
    @ResponseBody
    @RequestMapping(method = RequestMethod.POST)
    public String addPerson(HttpServletRequest request) {
        String firstName = request.getParameter("first_name");
        String lastName = request.getParameter("last_name");
        Person person = new Person(firstName, lastName);
        log.info(person.toString());
        return person.toString();
    }
}

這樣的代碼強(qiáng)依賴了javax.servlet-api的HttpServletRequest對(duì)象,并且把初始化Person對(duì)象這“活兒”加塞給了controller。代碼顯得累贅不優(yōu)雅。在controller里我只想使用person而不想組裝person,想要類似下面的代碼:

@RequestMapping(method = RequestMethod.POST)
public String addPerson(Person person) {
  log.info(person.toString());
  return person.toString();
}

直接在形參列表中獲得person。那么這該如實(shí)現(xiàn)呢?

我們需要定義如下的一個(gè)參數(shù)分解器

package com.demo.mvc.component;
import org.springframework.core.MethodParameter;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;
import com.demo.domain.Person;
public class PersonArgumentResolver implements HandlerMethodArgumentResolver {
    @Override
    public boolean supportsParameter(MethodParameter parameter) {
        return parameter.getParameterType().equals(Person.class);
    }
    @Override
    public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
        String firstName = webRequest.getParameter("first_name");
        String lastName = webRequest.getParameter("last_name");
        return new Person(firstName, lastName);
    }
}

在supportsParameter中判斷是否需要啟用分解功能,這里判斷形參類型是否為Person類,也就是說當(dāng)形參遇到Person類時(shí)始終會(huì)執(zhí)行該分解流程resolveArgument,也可以基于paramter上是否有我們指定的自定義注解判斷是否需要流程分解。在resolveArgument中處理person的初始化工作。

注冊(cè)自定義分解器

傳統(tǒng)XML配置:

<mvc:annotation-driven>
      <mvc:argument-resolvers>
        <bean class="com.demo.mvc.component.PersonArgumentResolver"/>
      </mvc:argument-resolvers>
</mvc:annotation-driven>

<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
    <property name="customArgumentResolvers">
          <bean class="com.demo.mvc.component.PersonArgumentResolver"/>
    </property>
</bean>

spring boot java代碼配置:

public class WebConfig extends WebMvcConfigurerAdapter{
    @Override
    public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
        argumentResolvers.add(new CustomeArgumentResolver());
    }
}

SpringMVC技巧之通用Controller

一個(gè)通用Controller。大多數(shù)情況下不再需要編寫任何Controller層代碼,將開發(fā)人員的關(guān)注點(diǎn)全部集中到Service層。

1. 前言

平時(shí)在進(jìn)行傳統(tǒng)的MVC開發(fā)時(shí),為了完成某個(gè)特定的功能,我們通常需要同時(shí)編寫Controller,Service,Dao層的代碼。代碼模式大概是這樣的。

這里只貼出Controller層的代碼,Service層也不是本次我們的關(guān)注點(diǎn)。

// ----------------------------------------- Controller層
@RestController
@RequestMapping("/a")
public class AController {
 @Resource(name = "aService")
 private AService aService;
 
 @PostMapping(value = "/a")
 public ResponseBean<String> a(HttpServletRequest request, HttpServletResponse response) {
  final String name = WebUtils.findParameterValue(request, "name");
  return ResponseBean.of(aService.invoke(name));
 }
}
// ----------------------------------------- 前端訪問路徑
// {{rootPath}}/a/a.do

2. 問題

只要有過幾個(gè)月Java Web開發(fā)經(jīng)驗(yàn)的,應(yīng)該對(duì)這樣的代碼非常熟悉,熟悉到惡心。我們稍微注意下就會(huì)發(fā)現(xiàn):上面的Controller代碼中,大致做了如下事情:

收集前端傳遞過來的參數(shù)。

將第一步收集來的參數(shù)傳遞給相應(yīng)的Service層的某個(gè)方法執(zhí)行。

將Service層執(zhí)行后的結(jié)果使用Controller層特有的ResponseBean進(jìn)行封裝后返回給前臺(tái)。

所以我們?cè)谂懦羯儆械奶厥馇闆r之后,就會(huì)發(fā)現(xiàn)在一般情況下這個(gè)所謂的Controller層的存在感實(shí)在有點(diǎn)稀薄。因此本文嘗試去除掉這部分枯燥的重復(fù)性代碼。

3. 解決方案

直接上代碼。talk is cheap, show me the code。

// 這里之所以是 /lq , 而不是 /* ; 是因?yàn)?AntPathMatcher.combine 方法中進(jìn)行合并時(shí)的處理, 導(dǎo)致 前一個(gè) /* 丟失
/**
 * <p> 直接以前端傳遞來的Serivce名+方法名去調(diào)用Service層的同名方法; Controller層不再需要寫任何代碼
 * <p> 例子
 * <pre>
 *   前端: /lq/thirdService/queryTaskList.do
 *   Service層相應(yīng)的方法簽名:  Object queryTaskList(Map<String, Object> parameterMap)
 *   相應(yīng)的Service注冊(cè)到Spring容器中的id : thirdServiceService
 * </pre>
 * @author LQ
 *
 */
@RestController
@RequestMapping("/lq")
public class CommonController {
 private static final Logger LOG = LoggerFactory.getLogger(ThirdServiceController.class);
 @PostMapping(value = "/{serviceName}/{serviceMethodName}")
 public void common(@PathVariable String serviceName, @PathVariable final String serviceMethodName, HttpServletRequest request, HttpServletResponse response) {
  // 收集前臺(tái)傳遞來的參數(shù), 并作預(yù)處理
  final Map<String, String> parameterMap = HtmlUtils.getParameterMap(request);
  final Map<String, Object> paramsCopy = preDealOutParam(parameterMap);
  // 獲取本次的調(diào)度服務(wù)名和相應(yīng)的方法名
  //final List<String> serviceAndMethod = parseServiceAndMethod(request);
  //final String serviceName = serviceAndMethod.get(0) + "Service";
  //final String serivceMethodName = serviceAndMethod.get(1);
  
  // 直接使用Spring3.x新加入的@PathVariable注解; 代替上面的自定義操作
  serviceName = serviceName + "Service";
  final String fullServiceMethodName = StringUtil.format("{}.{}", serviceName, serivceMethodName);
  // 輸出日志, 方便回溯
  LOG.debug("### current request method is [ {} ] ,  parameters is [ {} ]", fullServiceMethodName, parameterMap);
  // 獲取Spring中注冊(cè)的Service Bean
  final Object serviceBean = SpringBeanFactory.getBean(serviceName);
  Object rv;
  try {
   // 調(diào)用Service層的方法
   rv = ReflectUtil.invoke(serviceBean, serivceMethodName, paramsCopy);
   // 若用戶返回一個(gè)主動(dòng)構(gòu)建的FriendlyException
   if (rv instanceof FriendlyException) {
    rv = handlerException(fullServiceMethodName, (FriendlyException) rv);
   } else {
    rv = returnVal(rv);
   }
  } catch (Exception e) {
   rv = handlerException(fullServiceMethodName, e);
  }
  LOG.debug("### current request method [ {} ] has dealed,  rv is [ {} ]", fullServiceMethodName, rv);
  HtmlUtils.writerJson(response, rv);
 }
 /**
  * 解析出Service和相應(yīng)的方法名
  * @param request
  * @return
  */
 private List<String> parseServiceAndMethod(HttpServletRequest request) {
  // /lq/thirdService/queryTaskList.do 解析出 [ thirdService, queryTaskList ]
  final String serviceAndMethod = StringUtil.subBefore(request.getServletPath(), ".", false);
  List<String> split = StringUtil.split(serviceAndMethod, '/', true, true);
  return split.subList(1, split.size());
 }
 
 // 將傳遞來的JSON字符串轉(zhuǎn)換為相應(yīng)的Map, List等
 private Map<String, Object> preDealOutParam(final Map<String, String> parameterMap) {
  final Map<String, Object> outParams = new HashMap<String, Object>(parameterMap.size());
  for (Map.Entry<String, String> entry : parameterMap.entrySet()) {
   outParams.put(entry.getKey(), entry.getValue());
  }
  for (Map.Entry<String, Object> entry : outParams.entrySet()) {
   final String value = (String) entry.getValue();
   if (StringUtil.isEmpty(value)) {
    entry.setValue("");
    continue;
   }
   Object parsedObj = JSONUtil.tryParse(value);
   // 不是JSON字符串格式
   if (null == parsedObj) {
    continue;
   }
   entry.setValue(parsedObj);
  }
  return outParams;
 }
 // 構(gòu)建成功執(zhí)行后的返回值
 private Object returnVal(Object data) {
  return MapUtil.newMapBuilder().put("data", data).put("status", 200).put("msg", "success").build();
 }
 // 構(gòu)建執(zhí)行失敗后的返回值
 private Object handlerException(String distributeMethod, Throwable e) {
  final String logInfo = StringUtil.format("[ {} ] fail", distributeMethod);
  LOG.error(logInfo, ExceptionUtil.getRootCause(e));
  return MapUtil.newMapBuilder().put("data", "").put("status", 500)
    .put("msg", ExceptionUtil.getRootCause(e).getMessage()).build();
 }
}

4. 使用

到此為止,Controller層的代碼就算是完成了。之后的開發(fā)工作中,在絕大多數(shù)情況下,我們將不再需要編寫任何Controller層的代碼。只要遵循如下的約定,前端將會(huì)直接調(diào)取到Service層的相應(yīng)方法,并獲取到約定格式的響應(yīng)值。

  • 前端請(qǐng)求路徑 : {{rootPath}}/lq/serviceName/serviceMethodName.do
  • {{rootPath}} : 訪問地址的根路徑
  • lq :自定義的固定名稱,用于滿足SpringMVC的映射規(guī)則。
  • serviceName : 用于獲取Spring容器中的Service Bean。這里的規(guī)則是 該名稱后附加上Service字符來作為Bean Id來從Spring容器中獲取相應(yīng) Service Bean。
  • serviceMethodName : 第三步中找到的Service Bean中的名為serviceMethodName的方法。簽名為Object serviceMethodName(Map<String,Object> param)。

5. 特殊需求

對(duì)于有額外需要的特殊Controller,可以完全按照之前的Controller層寫法。沒有任何額外需要注意的地方。

6. 完善

上面的Service層的方法簽名中,其參數(shù)使用的是固定的Map<String,Object> param。對(duì)Map和Bean的爭(zhēng)論由來已久,經(jīng)久不衰,這里不攪和這趟渾水。

對(duì)于希望使用Bean作為方法參數(shù)的,可以參考SpringMVC中對(duì)Controller層方法調(diào)用的實(shí)現(xiàn),來達(dá)到想要的效果。具體的實(shí)現(xiàn)就不在這里獻(xiàn)丑了,有興趣的同學(xué)可以參考下源碼ServletInvocableHandlerMethod.invokeAndHandle。

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • Java?List集合取交集的8種不同實(shí)現(xiàn)方式總結(jié)

    Java?List集合取交集的8種不同實(shí)現(xiàn)方式總結(jié)

    工作中經(jīng)常遇到需要取兩個(gè)集合之間的交集、差集情況,下面這篇文章主要給大家總結(jié)介紹了關(guān)于Java?List集合取交集的8種不同實(shí)現(xiàn)方式,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2024-04-04
  • Spring Boot獲取微信用戶信息的超簡(jiǎn)單方法

    Spring Boot獲取微信用戶信息的超簡(jiǎn)單方法

    這篇文章主要給大家介紹了關(guān)于Spring Boot獲取微信用戶信息的超簡(jiǎn)單方法,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用Spring Boot具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-09-09
  • SpringCloud Alibaba微服務(wù)實(shí)戰(zhàn)之遠(yuǎn)程Feign請(qǐng)求頭丟失問題解決方案

    SpringCloud Alibaba微服務(wù)實(shí)戰(zhàn)之遠(yuǎn)程Feign請(qǐng)求頭丟失問題解決方案

    這篇文章主要介紹了SpringCloud Alibaba微服務(wù)實(shí)戰(zhàn)之遠(yuǎn)程Feign請(qǐng)求頭丟失問題,對(duì)SpringCloud Alibaba Feign請(qǐng)求頭問題感興趣的朋友跟隨小編一起看看吧
    2024-02-02
  • Java?volatile關(guān)鍵字特性講解下篇

    Java?volatile關(guān)鍵字特性講解下篇

    JMM要求保證可見性、原子性、有序性,volatile可以保證其中的兩個(gè),本篇文章具體驗(yàn)證volatile的可見性,不原子性和禁重排,同時(shí)解決volatile的不保證原子性,讓代碼具有原子性
    2022-12-12
  • Mybatis的Mapper代理對(duì)象生成及調(diào)用過程示例詳解

    Mybatis的Mapper代理對(duì)象生成及調(diào)用過程示例詳解

    這篇文章主要為大家介紹了Mybatis的Mapper代理對(duì)象生成及調(diào)用過程示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-09-09
  • Plugin ‘org.springframework.boot:spring-boot-maven-plugin:‘ not found的解決方案(親測(cè)可用)

    Plugin ‘org.springframework.boot:spring-boot-maven-plug

    這篇文章給大家介紹了Plugin ‘org.springframework.boot:spring-boot-maven-plugin:‘ not found的解決方案,親測(cè)可用,文中給出了兩種解決方法,需要的朋友可以參考下
    2024-01-01
  • Java靜態(tài)和非靜態(tài)成員變量初始化過程解析

    Java靜態(tài)和非靜態(tài)成員變量初始化過程解析

    這篇文章主要介紹了Java靜態(tài)和非靜態(tài)成員變量初始化過程解析,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-01-01
  • Java序列化中子類、父類構(gòu)造函數(shù)問題實(shí)例分析

    Java序列化中子類、父類構(gòu)造函數(shù)問題實(shí)例分析

    這篇文章主要介紹了Java序列化中子類、父類構(gòu)造函數(shù)問題,結(jié)合實(shí)例形式分析了java父類與子類構(gòu)造函數(shù)中序列化接口調(diào)用相關(guān)操作技巧與使用注意事項(xiàng),需要的朋友可以參考下
    2019-09-09
  • 淺析Java中接口和抽象類的七大區(qū)別

    淺析Java中接口和抽象類的七大區(qū)別

    Java 是一門面向?qū)ο蟮木幊陶Z言,面向?qū)ο蟮木幊陶Z言有四大特征:抽象、封裝、繼承和多態(tài)。本文介紹的接口和抽象類就是面向?qū)ο缶幊讨小俺橄蟆钡木唧w實(shí)現(xiàn)。本文也將為大家詳細(xì)講一下二者的區(qū)別,需要的可以參考一下
    2021-12-12
  • SpringBoot獲取配置文件中的配置項(xiàng)的常用方式

    SpringBoot獲取配置文件中的配置項(xiàng)的常用方式

    這篇文章主要介紹了SpringBoot獲取配置文件中的配置項(xiàng)的常用方式,并通過代碼示例講解的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作有一定的幫助,需要的朋友可以參考下
    2024-11-11

最新評(píng)論

贡嘎县| 白城市| 白水县| 上林县| 建宁县| 龙岩市| 青阳县| 宜昌市| 舞阳县| 定兴县| 安泽县| 普兰店市| 札达县| 临潭县| 衡水市| 阜平县| 金昌市| 克拉玛依市| 烟台市| 防城港市| 涞水县| 壤塘县| 岳阳市| 德兴市| 文安县| 邵东县| 富蕴县| 南江县| 讷河市| 措美县| 阿荣旗| 勃利县| 昭觉县| 桦川县| 宁阳县| 阿荣旗| 黑河市| 鄱阳县| 杂多县| 顺义区| 马边|