springboot web项目搭建(二)

版权声明:本文为博主原创文章,如需转载请注明出处 https://blog.csdn.net/linghuanxu/article/details/88937995

前言

之前有一篇文章是介绍springmvc环境的搭建以及jpa和mybatis同时使用的项目搭建的(https://blog.naturetrible.com/index.php/72/research/nature/ ) 。但是吧,最近几个月的项目我们已经完全放弃jpa以及hibernate的兼容性了,同时,我在现在的环境搭建中也基本使用纯注解的配置,spring的版本也升级到了5.0,所以,这一次我还是决定重新写一篇搭建项目的文章,并把我提取出来的常用配置及相关代码附上。
  代码的基础是上一篇springboot web项目搭建( https://blog.naturetrible.com/index.php/290/research/set-up-background-framework/nature/ )的基础上写的。
  本文我们会主要解决这么几个问题:

  • 接口访问: 鉴于本次搭建打算做前后端分离,故,就不介绍如何添加服务端视图脚本解析的内容了,但是会说一下静态文件可以放在哪里。
  • json序列化: 由于前后端交互以及移动端交互,均需要通过json进行报文的转化,但是前端又有一些常见的坑,故,这里会提供一些通用的代码用来解决这些问题。
  • cors配置 这个配置在前后端分离中基本是必备的内容

接口访问

基础接口

因为我们所有的操作都需要进行接口访问,所以,这里我们就直接编写cors的demo,借以写一个接口。而现在springboot编写一个可以被访问的url也是简单得很。首先,我们新建一个包:com.ntbrick.management.platform.cors ,里面新建一个类CorsController。这个就是我们的控制类了。现在CorsController的代码如下:

@RestController
@RequestMapping("/cors")
public class CorsController{

    @RequestMapping("/test")
    public void testCors(){
    }
}

这里构成了一个最基本的可以被访问的控制器,我们从上倒下一点一点得讲各部分都是什么意思,什么作用:

  • @RestController: 这个注解打在类上有两个意思,首先,这个是个Controller,而在spring中,所有的Cntroller都是Bean,所以,我们的Controller的bean就注册完成了。而之所以我们打的注解是RestController而不是Controller,因为我们这个controller里都是接口,返回的是返回值的json序列化内容,而不是视图的uri,如果使用Controller注解,则需要在每个action上面再加上@ResponseBody注解。
  • @RequestMapping("/cors"): 这个注解是用来定义uri的,这里是说这个controller中的uri都是使用/cors开头的。
  • @RequestMapping("/test") 这个注解是打在方法(action)上的,这样就和类上面的拼接上了,访问这个接口的uri是/cors/test。我使用的是默认端口8080。所以本地访问这个接口的地址就变成了 http://127.0.0.1:8080/cors/test 。启动项目后,我们把这个地址输入到浏览器或者postman里,就可以看到访问效果了。其实是没有返回值的,但是,如果你在方法里打断点是可以进入的。
      基本的接口就是这个样子,但是,这个接口其实没多少实际意义,现实中我们也很少用这种没有入参没有返回值的接口,所以,接下来我们向里面添加入参和返回值。不过,我这个例子里加入了我写项目的公共代码,我大概展示一下吧。

DefaultResponse

首先是DefaultReponse,这是一个默认的返回值类,其中定义了我业务返回值的默认接口,前端的业务编码也依据此结构来进行判断,而结构也相当简单,重点是其中使用了泛型,在反序列化之后可以进行方便得操作。代码如下:

package com.ntbrick.web.basic;

/**
 * 默认的api接口返回值结构
 * @author nature
 */
public class DefaultResponse<T> {

    public static final int SUCCESS_CODE=0;//成功返回值
    public static final int DEFAULT_FAILED_CODE=1;//默认的失败返回值
    public static final int NEED_AUTH_CODE=-2;//需要认证的返回值
    public static final int SYS_ERROR_CODE=-1;//系统异常

    private String msg;
    private int code;
    private T data;

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }

    public int getCode() {
        return code;
    }

    public void setCode(int code) {
        this.code = code;
    }

    public T getData() {
        return data;
    }

    public void setData(T data) {
        this.data = data;
    }
}

BaseController

建议每个项目都有自己的BaseController,这样在添加统一控制或者上下文的时候。我这里添加的主要是快速构建DefaultResponse返回值的相关方法,目前没有多少必要的功能。源码如下:

package com.ntbrick.web.basic;

import com.ntbrick.framework.core.utils.ValidateUtil;

/**
 * 所有控制器的基类,所有的控制器均应该继承该类
 * 该类提供了控制公用的方法的封装,以减少重复代码量
 * @author nature
 */
public class BaseController {


    /**
     * 获取成功返回对象
     * @param <T> 数据类型
     * @return 返回构造好的成功值返回对象
     */
    protected <T> DefaultResponse<T> successResponse(String msg){

        String message=msg;
        if(!ValidateUtil.strNotEmptyWithTrim(msg,null,null)){
            message="处理成功";
        }

        return this.buildResposne(null
                ,DefaultResponse.SUCCESS_CODE
                ,message);

    }
    /**
     * 获取成功返回对象
     * @param <T> 数据类型
     * @return 返回构造好的成功值返回对象
     */
    protected <T> DefaultResponse<T> successResponse(T data){


        return this.buildResposne(data
                ,DefaultResponse.SUCCESS_CODE
                ,"请求成功");

    }

    /**
     * 构建失败返回对象
     * @param data 需要返回的数据
     * @param msg 失败提示信息,如果为空的话则返回默认值
     * @param <T> 数据类型
     * @return 返回构造好的失败返回对象
     */
    protected <T> DefaultResponse<T> failedResponse(T data,String msg){

        String message=msg;
        if(ValidateUtil.strNotEmptyWithTrim(msg,null,null)){
            message="处理异常";
        }

        return this.buildResposne(data
                ,DefaultResponse.DEFAULT_FAILED_CODE
                ,message);

    }

    /**
     * 帮助构造返回值对象那个
     * @param data 需要返回的数据
     * @param code 返回值code
     * @param msg 提示信息,如果为空的话则返回默认值
     * @param <T> 数据类型
     * @return 构造好的返回值对象
     */
    protected <T> DefaultResponse<T> buildResposne(T data,int code,String msg){
        DefaultResponse<T> response=new DefaultResponse<>();
        response.setMsg(msg);
        response.setCode(code);
        response.setData(data);

        return response;
    }
}

需要注意的是这里有这么个类:com.ntbrick.framework.core.utils.ValidateUtil,这个是我core包里面的类,用来封装常见的校验的,相信根据方法名已经能看到它是干什么用的了。

带入参返回值的接口

这个改造我们还是先上代码哈:

@RestController
@RequestMapping("/cors")
public class CorsController extends BaseController {

    @RequestMapping("/test")
    public DefaultResponse testCors(@RequestBody Map<String,String> request){
        return this.successResponse(request);
    }
}

可以看到,CorsController多了个基类,testCors方法多了返回值和入参。基类的事我们就不说了,我们说说testCors的入参和返回值。返回值比较简单,我们先说返回值。我们仅把返回值类型由void改成了DefaultResponse,本来还需要一个ResponseBody注解将DefaultResponse的json序列化结果放到返回的报文的body部分,但是因为我们使用了RestController,就不用打了。
  再看下入参,@RequestBody Map<String,String> request 其实就是在一般的入参上多了个RequestBody的注解。原因是,我们约定,所有的请求的contenttype都是application/json,而json字符串是放在http报文的body中的,所以,我们会这么接收参数,这里还有相应的注解可以获取header、form中的值,具体还是自己查阅吧,很简单。这个时候尝试构建请求,就可以正常访问了。
  我这里测试的页面内容如下,位置可以直接放在resourc的public文件夹下,那里是默认的静态资源文件夹

<!DOCTYPE html>
<html>
<head>
</head>
<body>
<script src="./plugins/jquery/jquery.min.js"></script>
<script src="./js/common.js"></script>
<script>
    $(document).ready(function($){
      CommonTools.request("post","http://localhost:8080/cors/test",{
      	test:"2",
      	cors:"test"
      },function (response) {
          console.log(response);
      })
    });
</script>
</body>

对应的静态你文件就自己添加吧,我用的CommonTools.request的方法的代码如下:

CommonTools.request=function(requestType, url, requestData, successFunction){
    // Layer.loading();
    $.ajax({
        type:requestType,
        url:url,
        dataType:'json',
        headers:CommonTools.getHeader(),
        data:JSON.stringify(requestData),
        success:function(response) {
            if (response.code == -1) {
                CommonTools.hint("系统异常,请联系管理员");
            }
            else{
                successFunction(response);
            }
        },
        error:function(error){
            CommonTools.hint("服务器异常,请联系管理员");
        }
    });
};

CommonTools.hint是信息弹出的封装方法,可以去掉也可以自己看着写,总之,就是酱紫了。酱紫我们就完成了基本的接口请求和测试了。

Json序列化

看了上面的接口实现代码,入参,返回值我们都只到是什么了,也可以在方法中加入对应的业务处理。但是,json数据是怎么转化成这个方法的入参,返回值又是怎么转化成json字符串的。如果转化或者识别得有问题,能不能自己控制,这个问题其实是隐藏的,但是,你会发现,你测试的时候是没问题的。因为在springboot中有默认的转换器,使用的是MappingJackson2HttpMessageConverter 。基本上可以满足大部分的需求了,但是,常见的坑还是有的:

  • 日期格式后的格式是不常用的,在js和java的通信时,存在问题,我个人习惯把日期格式转化成yyyy-MM-dd HH:mm:ss格式
  • 在页面中,long数字过大时,低位会被抹零导致数据不对,我们需要把long转换成字符串进行处理,以确保数据不会被改变。

这些东西,我们通过给spring增加配置来解决,我的代码因为有提炼,所以变成了一个基础配置类和一个具体的配置类,具体的配置类如下:

package com.ntbrick.management.platform.config;

import com.ntbrick.web.config.BaseWebConfig;
import org.springframework.context.annotation.Configuration;

@Configuration
public class WebConfig extends BaseWebConfig {
}

这里需要注意的是Configuration注解,这个注解有两个含义,首先,这个类,变成了一个bean,其次,这个类是一个配置类,spring会使用它进行配置。所以,注意类方的位置,需要被spring扫描到。而继承的BaseWebConfig是我提炼出来的类,因为我每个都有这些配置,代码如下:

package com.ntbrick.web.config;

public abstract class BaseWebConfig implements WebMvcConfigurer {

    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        MappingJackson2HttpMessageConverter jackson2HttpMessageConverter = new MappingJackson2HttpMessageConverter();
        ObjectMapper objectMapper = new ObjectMapper();
        SimpleModule simpleModule = new SimpleModule();
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        objectMapper.setDateFormat(dateFormat);
        //不显示为null的字段
//        objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
        simpleModule.addSerializer(Long.class, ToStringSerializer.instance);
        simpleModule.addSerializer(Long.TYPE, ToStringSerializer.instance);
        objectMapper.registerModule(simpleModule);
        jackson2HttpMessageConverter.setObjectMapper(objectMapper);
        //放到第一个
        converters.add(0,jackson2HttpMessageConverter);
    }

}

这里需要注意的是,我们实现了一个WebMvcConfigurer类,在4.0.3以前,需要继承一个类,类名我忘了,这里是因为java8引入了接口的默认实现,之前因为要默认实现所以只能使用抽象类,具体没有多大变化。我们重写了configureMessageConverters方法,中天添加的代码大家应该是可以看懂的,我就不过多的解释了,做的事也就是解决我们之前的两个问题。理论上来说,这是需要在application类上打@EnableWebMvc注解的,但是,我没打也生效了,应该是哪里的约定吧,总之,如果没生效,可以尝试加上这个注解。

cors配置

其实吧,这个配置非常简单,在刚才的配置类上添加如下代码即可:

    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**");
    }

现在我们来说说,什么是cors,以及我们为什么要在这个项目里专门提这么个东西吧。
  CORS,全称Cross-Origin Resource Sharing,是一种允许当前域(domain)的资源(比如html/js/web service)被其他域(domain)的脚本请求访问的机制,通常由于同域安全策略(the same-origin security policy)浏览器会禁止这种跨域请求。具体的过程可以细查一下,总之,现在的情况是,spring内置了这种支持,而且我现在经过这种配置,它在我的全局生效了。当然了,有人指向某个或者某几个请求生效,那可以直接在方发生标记@CrossOrigin即可。这时候,把我们之前的网页在iis,或者直接用hbuider运行起来,访问服务接口,可以看到跨域也是可以访问的,在配置之前是会报403的。

总结

至此,我们的基本web项目接口就搭建完成了。不过懂行的指导,其实还有一些关键功能没介绍,这些,我们在后面使用到的具体功能的地方进行介绍,本章到此结束。

猜你喜欢

转载自blog.csdn.net/linghuanxu/article/details/88937995