前后端传参范例

前后端传参范例

  • 目录
    • 概述
      • 需求:
    • 设计思路
    • 实现思路分析
      • 1.基本传值:
      • 2.框架层
        • 2.1 @RequestParam(name = “column”, required = false)
        • 2.2 集合对象变量:
        • 2.3.单个类对象: @RequestBody @Valid MembersAssessmentConfigDto dto
        • 2.4.多个集合对象:@RequestBody Map map
      • 3.复杂组合传值用:
    • 拓展实现
      • 1.request
      • @param
      • @PathVariable
      • @RequestBody
        • 还有最基本的一个
  • 参考资料和推荐阅读

Survive by day and develop by night.
talk for import biz , show your perfect code,full busy,skip hardness,make a better result,wait for change,challenge Survive.
happy for hardess to solve denpendies.

目录

在这里插入图片描述

概述

接口通信范例是一个常见的任务和功能,在前后台交互中有着非常重要的作用。
上个系列中谈到了几个范例,我们今天来实现部分。如下:
1.基本参数传值:

2.框架层:
单个基本变量用:
集合对象变量:
单个类对象:
多个集合对象:

3.复杂组合传值用:

基本实现还是借助框架的@RequestParam @RequestBody@PathVariable)3个要素实现。

需求:

1.1.基本传值:
2. 框架层:
3. 复杂组合传值用:

设计思路

实现思路分析

1.基本传值:

基本传值传送的是HttpServletRequest 对象,接收的对象是HttpServletResponse ,获取对应的参数是getParamter.(“XXX”)
前台传送的XXX组件的数值即可

public R list(Pageable pageable, HttpServletRequest request) {

        Map<String, Object> params = new HashMap<String, Object>();
        params.put("pageable", pageable);
        params.put("notCategoryId", 1);
        Page<Map<String, Object>> page = articleService.findPageByParams(params);

        Iterator<Map<String, Object>> iterator = page.getContent().iterator();
        while (iterator.hasNext()) {
            Map<String, Object> mp = iterator.next();
            mp.put("createDate", DateUtils.dateToString((Date) mp.get("createDate"), "yyyy-MM-dd"));
        }
        Map responseData = new Hashtable();
        responseData.put("page", page);
        Map<String, Object> data = new HashMap<String, Object>();

//        data.put("type", 2);
        //  data.put("grade", 1);
        List<HashMap<String, Object>> articleCategoryPage = articleCategoryService.findListByParams(data);
        Iterator<HashMap<String, Object>> iterator2 = articleCategoryPage.iterator();
        while (iterator2.hasNext()) {
            Map<String, Object> mp = iterator2.next();
            mp.put("createDate", DateUtils.dateToString((Date) mp.get("createDate"), "yyyy-MM-dd"));
        }
        responseData.put("articleCategoryPage", articleCategoryPage);
        /*按钮权限*/
        //List permsList  = (List) request.getSession().getAttribute(SysAdmin.ADMIN_PERMS);
        //model.addAttribute("permsList",permsList);
        //	model.addAttribute("setting",sysConfigService.get());
        return R.ok(responseData);
    }

2.框架层

2.1 @RequestParam(name = “column”, required = false)
 @RequestMapping(value = "/list", method = RequestMethod.POST)
    public R list(String startDate, String endDate, String name, String date, Long adLocationId, Integer isShow, Integer pageNo) {
        Map<String, Object> params = new HashMap<String, Object>();
        params.put("pageable", new Pageable(pageNo, 20));
        params.put("startDate", startDate);
        params.put("endDate", endDate);
        params.put("name", name);
        params.put("adLocationId", adLocationId);
        params.put("isShow", isShow);
      //  int[] adLocationIds = {1, 2};
        //params.put("netAdLocationIds", adLocationIds);
        params.put("netAdLocationIds", null);
        Page<Map<String, Object>> page = adService.findPageByParams(params);
        for (Map<String, Object> ss : page.getContent()) {

            ss.put("startDate", DateUtils.dateToString((Date) ss.get("startDate"), DateUtils.patternD));
            ss.put("endDate", DateUtils.dateToString((Date) ss.get("endDate"), DateUtils.patternD));
        }
        R r = R.ok();
        r.put("page", page);
        r.put("total", page.getTotal());

        return r;
2.2 集合对象变量:

这里常用的是@RequestBody List companyIds,等集合对象接收。

/**
     * 文本编辑器上传
     */
    @PostMapping(value = "/editor_upload")
    public Object editorUpload(@RequestParam("file[]") MultipartFile file[]) {
        FileType ft = FileType.image;
        List<Object> dataList = new ArrayList<>();
        for (MultipartFile imgFile : file) {
            if (!this.filesService.isValid(ft, imgFile)) {
                throw new RuntimeException("上传失败");
            }

            Files f = this.filesService.upload(ft, imgFile, 0);
            if (f == null) {
                throw new RuntimeException("上传失败");
            }

            Map<String, Object> data = new HashMap<>();
            data.put("url", f.getAbsolute());
            data.put("name", f.getName());
            data.put("error", 0);
            dataList.add(data);

        }


        return dataList;
    }
2.3.单个类对象: @RequestBody @Valid MembersAssessmentConfigDto dto
    @PostMapping(value = "/editor")
    public Object editorUpload(@RequestBody @Valid MembersAssessmentConfigDto dto) MultipartFile file[]) {
        FileType ft = FileType.image;
        List<Object> dataList = new ArrayList<>();
        for (MultipartFile imgFile : file) {
            if (!this.filesService.isValid(ft, imgFile)) {
                throw new RuntimeException("上传失败");
            }

            Files f = this.filesService.upload(ft, imgFile, 0);
            if (f == null) {
                throw new RuntimeException("上传失败");
            }

            Map<String, Object> data = new HashMap<>();
            data.put("url", f.getAbsolute());
            data.put("name", f.getName());
            data.put("error", 0);
            dataList.add(data);

        }


        return dataList;
    }
2.4.多个集合对象:@RequestBody Map map

这里前台可以使用对应的list 传值。或者map传值通常用于批处理。

 public R save(@RequestBody Map<String, PsDeptCostDto> map) {

        if (StringUtils.isBlank(name)) {
            return R.error("角色名称不能为空");
        }
        String[] idsArr = null;
        if (StringUtils.isNotBlank(ids)) {
            idsArr = ids.split(",");
        }
        Long[] menuIds = null;
        if (idsArr != null && idsArr.length > 0) {
            menuIds = new Long[idsArr.length];
            for (int i = 0; i < idsArr.length; i++) {
                menuIds[i] = Long.parseLong(idsArr[i]);
            }
        }
        SysAdmin sa = ShiroUtils.getSysAdmin();

        sysRoleService.saveSupplierRole(name, description, menuIds, sa.getSupplierId());
        return R.ok("添加成功");
    }

3.复杂组合传值用:

这里集中了最复杂的组合式传参的方法:
代码如下:

  public R del(@RequestBody MembersAssessmentConfigDto dto,
@RequestParam(name = “column”, required = false) String sortColumn,
@RequestParam(name = “order”, defaultValue = “ASC”, required = false) String sortType,
HttpServletRequest req
)) {
        if (ids == null || ids.length == 0) {
            return R.error("请选择角色");
        }
        sysRoleService.deleteByPrimaryKeys(ids);
        ShiroUtils.clearCachedAuthorizationInfo();
        return R.ok("删除成功");
    }

拓展实现

1.request

无论是的jsp的方法,还是html得ajax方法,本质上是servlet的方法,springmvc,nutz都是对其的封装,

request.getParameter()方法:1.获取通过http协议提交过来的数据. 通过容器的实现来取得通过get或者post方式提交过来的数据

request.getParameter()方法传递的数据,会从web客户端传到web服务器端,代表HTTP请求数据,该方法返回String类型的数据

request.setAttribute()和getAttribute()只是在web容器内部流转,仅仅是请求处理阶段

request.getAttribute()方法返回request范围内存在的对象

request.setAttribute() 和 getAttribute() 方法传递的数据只会存在于Web容器内部

HttpServletRequest 类有 setAttribute() 方法,而没有setParameter() 方法
一般通过表单和链接传递的参数使用getParameter.

@param

springMVC的实现类是RequestParamMethodArgumentResolver。
该实现类支持处理有@RequestParam注解的参数:
实现逻辑如下:
根据方法入参获取参数配置信息(调用抽象方法createNamedValueInfo获取,这里就是拿到参数的@RequestParam注解属性)

根据参数配置的name获取真正的参数name(有的子类在1中返回的name可能是占位符或表达式,所以需要处理,这里就是@RequestParam的name值)
根据参数name得到参数值(调用模板方法resolveName),若为null或空但配有默认值,则参数值为resolveStringValue方法(即2中方法)返回值;若为null且必填,调用handleMissingValue方法抛出异常;若为null但非必填,则参数值为handleNullValue方法返回值(若参数是Boolean类型,返回false,否则抛异常)
再调用空方法handleResolvedValue(留给子类@Override从而实现特殊逻辑,这里未覆盖)
返回参数值

@PathVariable

RequestParam几乎一样,简单的提取注解属性。
RequestMappingInfoHandlerMapping在lookupHandlerMethod方法中解析请求路径并匹配到处理器后,调用handleMatch方法解析请求路径和RequestMappingInfo里的路径后设置的

@RequestBody

找出能处理此请求contentType的实现类,在解析前后又插入了RequestBodyAdvice增强类的逻辑。

protected <T> Object readWithMessageConverters(HttpInputMessage inputMessage, MethodParameter parameter,
                                               Type targetType) throws IOException, HttpMediaTypeNotSupportedException, HttpMessageNotReadableException {

    MediaType contentType;
    boolean noContentType = false;
    try {
       //1.调用HttpServletRequest相关方法获取ContentType
        contentType = inputMessage.getHeaders().getContentType();
    }
    catch (InvalidMediaTypeException ex) {
        throw new HttpMediaTypeNotSupportedException(ex.getMessage());
    }
    if (contentType == null) {
        noContentType = true;
        contentType = MediaType.APPLICATION_OCTET_STREAM;
    }

    Class<?> contextClass = parameter.getContainingClass();
    Class<T> targetClass = (targetType instanceof Class ? (Class<T>) targetType : null);
    if (targetClass == null) {
        ResolvableType resolvableType = ResolvableType.forMethodParameter(parameter);
        targetClass = (Class<T>) resolvableType.resolve();
    }

    HttpMethod httpMethod = (inputMessage instanceof HttpRequest ? ((HttpRequest) inputMessage).getMethod() : null);
    Object body = NO_VALUE;

    EmptyBodyCheckingHttpInputMessage message;
    try {
        message = new EmptyBodyCheckingHttpInputMessage(inputMessage);
        //2.遍历messageConverters
        for (HttpMessageConverter<?> converter : this.messageConverters) {
            Class<HttpMessageConverter<?>> converterType = (Class<HttpMessageConverter<?>>) converter.getClass();
            GenericHttpMessageConverter<?> genericConverter =
                    (converter instanceof GenericHttpMessageConverter ? (GenericHttpMessageConverter<?>) converter : null);
            //如果HttpMessageConverter#canRead返回true,即支持处理该contentType类型
            if (genericConverter != null ? genericConverter.canRead(targetType, contextClass, contentType) :
                    (targetClass != null && converter.canRead(targetClass, contentType))) {
                //这里的body就是servletRequest.getInputStream()返回的InputStream
                if (message.hasBody()) {
                    //遍历匹配该参数的RequestBodyAdvice,调用其beforeBodyRead方法处理HttpInputMessage
                    HttpInputMessage msgToUse =
                            getAdvice().beforeBodyRead(message, parameter, targetType, converterType);
                    //执行HttpMessageConverter#read返回解析后的参数值
                    body = (genericConverter != null ? genericConverter.read(targetType, contextClass, msgToUse) :
                            ((HttpMessageConverter<T>) converter).read(targetClass, msgToUse));
                    //遍历匹配该参数的RequestBodyAdvice,调用其afterBodyRead方法处理body              
                    body = getAdvice().afterBodyRead(body, msgToUse, parameter, targetType, converterType);
                }
                else {
                    body = getAdvice().handleEmptyBody(null, message, parameter, targetType, converterType);
                }
                break;
            }
        }
    }
    catch (IOException ex) {
        throw new HttpMessageNotReadableException("I/O error while reading input message", ex, inputMessage);
    }

    if (body == NO_VALUE) {
        if (httpMethod == null || !SUPPORTED_METHODS.contains(httpMethod) ||
                (noContentType && !message.hasBody())) {
            return null;
        }
        throw new HttpMediaTypeNotSupportedException(contentType, this.allSupportedMediaTypes);
    }

    MediaType selectedContentType = contentType;
    Object theBody = body;
    LogFormatUtils.traceDebug(logger, traceOn -> {
        String formatted = LogFormatUtils.formatValue(theBody, !traceOn);
        return "Read \"" + selectedContentType + "\" to [" + formatted + "]";
    });

    return body;
}
还有最基本的一个

RequestParamMethodArgumentResolver解析的。

兜底逻辑支持处理文件类型参数(如MultipartFile),和一些简单类型(如基本类型、String、Date等)。如上图对文件上传等。

而解析逻辑其实和有@RequestParam注解时差不多,只是有注解时从注解name属性取参数名,没注解时取反射的参数名。

父类AbstractNamedValueMethodArgumentResolver调用getNamedValueInfo方法获取参数信息时,没有提到会调用updateNamedValueInfo方法更新参数配置信息
如果从子类createNamedValueInfo方法得到的配置信息里没有参数名,会使用反射参数名。

参考资料和推荐阅读

  1. 前后端通信参数问题.
  2. 前后端传参.
  3. 前后端参数传递总结.
  4. 前后端参数传递总结.

欢迎阅读,各位老铁,如果对你有帮助,点个赞加个关注呗!~

你可能感兴趣的:(#,协议接口调试tools,java,前端,javascript)