spring mvc 对RESTful的支持

RESTful


        一种软件架构风格、设计风格,而不是标准,只是提供了一组设计原则和约束条件。它主要用于客户端和服务器交互类的软件。基于这个风格设计的软件可以更简洁,更有层次,更易于实现缓存等机制。

      REST(英文:Representational State Transfer,简称REST)描述了一个架构样式的网络系统,比如 web 应用程序。它首次出现在 2000 年 Roy Fielding 的博士论文中,Roy Fielding是 HTTP 规范的主要编写者之一。在目前主流的三种Web服务交互方案中,REST相比于SOAP(Simple Object Access protocol,简单对象访问协议)以及XML-RPC更加简单明了,无论是对URL的处理还是对Payload的编码,REST都倾向于用更加简单轻量的方法设计和实现。值得注意的是REST并没有一个明确的标准,而更像是一种设计的风格。它是一种针对网络应用的设计和开发方式,可以降低开发的复杂性,提高系统的可伸缩性。

理解RESTful架构 - 阮一峰的网络日志

RESTful API 设计指南 - 阮一峰的网络日志

Spring MVC对RESTful的支持


       spring mvc 通过@PathVariable注解获取各类参数变量。@PathVariable允许对应的参数为空。

API设计

  • GET /collection:返回资源对象的列表(数组)

               获取图书信息列表:/book

  • GET /collection/resource:返回单个资源对象

               获取指定图书信息:/book/id

  • POST /collection:返回新生成的资源对象

               创建(保存)图书信息:/book

  • PUT /collection/resource:返回完整的资源对象

               修改(编辑)图书信息:/book

  • PATCH /collection/resource:返回完整的资源对象
  • DELETE /collection/resource:返回一个空文档

               删除图书信息:/book/id

       如获取一个图书信息:/book/1,其中1就是一个参数,它代表的是图书编号,只是它在url中传递,对此SpringMVC也提供了良好的支持.现在指定一个方法,它将只支持HTTP的GET请求,通过URL:/book/1来获取图书信息并且打印出json数据

      在IBM的开发者社区中有一篇非常好的文章,名为《使用Spring 3来创建RESTful Web Services》,讲解如何用Spring Web和Spring MVC来创建REST风格的Web Service。由于这篇文章已经讲得很好了,只给大家介绍下swagger2的使用

Swagger2简介【补充】


        Swagger 是一个规范和完整的框架,用于生成、描述、调用和可视化 RESTful 风格的 Web 服务。总体目标是使客户端和文件系统作为服务器以同样的速度来更新。文件的方法,参数和模型紧密集成到服务器端的代码,允许API来始终保持同步。

  作用:

  1.  接口的文档在线自动生成。
  2. 功能测试。

swagger2注解介绍:

    swagger通过注解表明该接口会生成文档,包括接口名、请求方法、参数、返回信息的等等,如: 

  • @ApiIgnore:使用注解忽略该API,不会参与文档生成
  • @ApiOperation:描述该api,如: @ApiOperation(value=”创建用户”, notes=”根据User对象创建用户”)
  • @ApiImplicitParam(name = “user”, value = “用户详细实体user”, required = true, dataType = “User”):描述参数信息
  • @Api:修饰整个类,描述Controller的作用
  • @ApiParam:单个参数描述
  • @ApiModel:用对象来接收参数
  • @ApiResponses:HTTP响应整体描述
  • @ApiProperty:用对象接收参数时,描述对象的一个字段

构建基于RESTful风格的图书服务(继承swagger2--非必须)

step1 :构建脚本

plugins {
    id 'war'
    id 'java'
}

group 'edu.uestc.avatar'
version '1.0-SNAPSHOT'
sourceCompatibility = 17

repositories {
    mavenLocal()//添加本地
    maven { url 'https://maven.aliyun.com/repository/central' } //私有仓库,阿里云镜像
    mavenCentral()
}

dependencies {
    implementation group: 'org.springframework', name: 'spring-webmvc', version: '5.3.20'
    implementation group: 'org.springframework', name: 'spring-test', version: '5.3.20'
    compileOnly group: 'javax.servlet', name: 'javax.servlet-api', version: '4.0.1'
    compileOnly group: 'javax.servlet.jsp', name: 'javax.servlet.jsp-api', version: '2.3.3'
    //lombok
    compileOnly group: 'org.projectlombok', name: 'lombok', version: '1.18.24'
    annotationProcessor 'org.projectlombok:lombok:1.18.24'

    implementation group: 'ch.qos.logback', name: 'logback-classic', version: '1.2.11'


    implementation group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: '2.13.1'
    implementation group: 'com.alibaba', name: 'druid', version: '1.2.10'
    implementation group: 'mysql', name: 'mysql-connector-java', version: '8.0.29'

    implementation group: 'org.mybatis', name: 'mybatis', version: '3.5.10'
    implementation group: 'org.mybatis', name: 'mybatis-spring', version: '2.0.7'
    implementation group: 'com.github.pagehelper', name: 'pagehelper', version: '5.3.0'
    implementation group: 'org.springframework', name: 'spring-jdbc', version: '5.3.20'

    implementation group: 'javax.servlet', name: 'jstl', version: '1.2'
    implementation group: 'taglibs', name: 'standard', version: '1.1.2'

    implementation group: 'com.google.guava', name: 'guava', version: '31.1-jre'
    implementation group: 'javax.validation', name: 'validation-api', version: '2.0.1.Final'
    //3.x版本不兼容,降低版本号,解决问题
    implementation group: 'io.springfox', name: 'springfox-swagger2', version: '2.9.2'
    implementation group: 'io.springfox', name: 'springfox-swagger-ui', version: '2.9.2'

    implementation group: 'com.fasterxml.jackson.datatype', name: 'jackson-datatype-jsr310', version: '2.13.3'

    //7.0.4.Final会导致版本不匹配问题
    implementation group: 'org.hibernate', name: 'hibernate-validator', version: '6.0.16.Final'


    testImplementation 'junit:junit:4.11'
    testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.1'
    testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.1'
}

test {
    useJUnitPlatform()
}
//构建的字符编码
tasks.withType(JavaCompile){
    options.encoding = 'UTF-8'
}

step2 初始化spring IoC上下文和初始化映射请求上下文

Spring IoC(root)容器配置

@Configuration  
@ComponentScan(basePackages = "edu.uestc.avatar",excludeFilters = @Filter(value= Controller.class))  
@PropertySource(value = "classpath:pool-config.properties",encoding = "UTF-8")  
@MapperScan(basePackages = "edu.uestc.avatar.mapper" )  
@EnableTransactionManagement  
public class RootConfig {  
    /** 
     * 配置数据源 
     */  
    @Bean  
    public DataSource dataSource(  
            @Value("${driverClassName}") String driverClass,  
            @Value("${url}") String url,  
            @Value("${jdbc.username}") String username,  
            @Value("${password}") String password,  
            @Value("${defaultAutoCommit}") boolean defaultAutoCommit,  
            @Value("${connectionProperties}") String connectionProperties) {  
        var dataSource = new DruidDataSource();  
        dataSource.setDriverClassName(driverClass);  
        dataSource.setUrl(url);  
        dataSource.setUsername(username);  
        dataSource.setPassword(password);  
        dataSource.setDefaultAutoCommit(defaultAutoCommit);  
        dataSource.setConnectionProperties(connectionProperties);  
        return dataSource;  
    }  
    /** 
     * 配置SqlSessionFactory 
     * SqlSessionFactory是产生SqlSession的基础,在MyBatis-Spring项目中提供了SqlSessionFactoryBean去支持SqlSessionFactory的配置 
     */  
    @Bean  
    public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception { 
          
        var factoryBean = new SqlSessionFactoryBean();  
//factory的setting配置
        var configuration = new org.apache.ibatis.session.Configuration();
        configuration.setMapUnderscoreToCamelCase(true);
        factoryBean .setConfiguration(configuration);
        //设置类型别名  
        factoryBean.setTypeAliasesPackage("edu.uestc.avatar.domain");  
        //设置数据源  
        factoryBean.setDataSource(dataSource);  
        //ResourcePatternResolver定义了getResources来查找资源,PathMatchingResourcePatternResolver提供了以classpath开头的通配符方式查询  
        var resourcePatternResolver = new PathMatchingResourcePatternResolver();   
        factoryBean.setMapperLocations(resourcePatternResolver.getResources("classpath*:com/wise/tiger/mapper/**/*.xml"));  
//配置pageHelper
        var pageInterceptor = new PageInterceptor();
        var prop = new Properties();
        prop.setProperty("helperDialect","mysql");
        prop.setProperty("rowBoundsWithCount","true");
        prop.setProperty("reasonable","true");
        pageInterceptor.setProperties(prop);
        factoryBean.setPlugins();
        return factoryBean.getObject();  
    }  
      
    /** 
     * 事务管理器(Mybaits采用DataSourceTransactionManger) 
     */  
    @Bean  
    public DataSourceTransactionManager transactionManager(DataSource dataSource) {  
        return new DataSourceTransactionManager(dataSource);  
    }  
}  

 数据源配置文件properties内容如下

driverClassName = com.mysql.cj.jdbc.Driver  
url = jdbc:mysql://192.168.134.128:3306/db_book  
jdbc.username = tiger  
password = tiger  
  
########## dbcp连接池基本属性 #############  
# 初始化连接  
initialSize=20  
#最大连接数量,设 0 为没有限制  
maxTotal = 0  
#最大空闲连接  
maxIdle = 10  
#最小空闲连接  
minIdle = 3  
#超时等待时间以毫秒为单位  
maxWaitMillis = 1000  
  
#JDBC驱动建立连接时附带的连接属性属性的格式必须为这样:[属性名=property;]  
#注意:"user" 与 "password" 两个属性会被明确地传递,因此这里不需要包含他们。  
connectionProperties = serverTimezone=UTC;useSSL=false;useUnicode=true;characterEncoding=utf-8;allowPublicKeyRetrieval=true  
  
#指定由连接池所创建的连接的自动提交(auto-commit)状态。如果指定为false表示关闭自动提交  
defaultAutoCommit = false  
  
#driver default 指定由连接池所创建的连接的只读(read-only)状态。默认false  
#如果没有设置该值,则“setReadOnly”方法将不被调用。(某些驱动并不支持只读模式,如:Informix)  
#defaultReadOnly=  
  
#driver default 指定由连接池所创建的连接的事务级别(TransactionIsolation)。  
#可用值为下列之一:(详情可见javadoc。)NONE,READ_UNCOMMITTED, READ_COMMITTED, REPEATABLE_READ, SERIALIZABLE  
#defaultTransactionIsolation = REPEATABLE_READ  

dispatcherServlet的URI映射关系配置Java代码 

/** 
 * @Description: DispatcherServlet 配置 
 * @author: <a href="mailto:1020zhaodan@163.com">Adan</a>  
 * @date: 2019年5月28日  上午10:00:31 
 * @version:1.0-snapshot 
 */  
@Configuration  
@ComponentScan(basePackages = "edu.uestc.avatar.web")  
@EnableWebMvc  
public class WebConfig implements WebMvcConfigurer{  
    //视图解析器  
    @Bean  
    public InternalResourceViewResolver viewResolver() {  
        var viewResolver = new InternalResourceViewResolver();  
        viewResolver.setPrefix("/WEB-INF/pages/");  
        viewResolver.setSuffix(".jsp");  
        return viewResolver;  
    }  
  
    @Override //静态资源不被前端控制器拦截  
    public void addResourceHandlers(ResourceHandlerRegistry registry) {  
        registry.addResourceHandler("/static/**")//添加静态资源的url-pattern  
            .addResourceLocations("/static/");  
    }  
      
}  

 servlet3.0规范允许没有web.xml配置,只需要使用注解就可以了。spring3.1之后的版本也提供了注解方式的配置, 该方式需要继承AbstractAnnotationConfigDispatcherServletInitializer类,然后实现它所定义的方法。

public class WebAppInitializer  extends AbstractAnnotationConfigDispatcherServletInitializer{  
    /** 
     * Spring IoC(root)容器配置 
     */  
    @Override  
    protected Class<?>[] getRootConfigClasses() {  
        return new Class<?>[] {RootConfig.class};  
    }  
  
    /** 
     * DispatcherServlet的URI映射关系配置 
     */  
    @Override  
    protected Class<?>[] getServletConfigClasses() {  
        return new Class<?>[] {WebConfig.class,Swagger2Config.class};  
    }  
      
    /** 
     * dispatcherServlet 拦截内容(什么请求交给前端控制器) 
     * <url-pattern>/</url-pattern> 
     */  
    @Override  
    protected String[] getServletMappings() {  
        return new String[] {"/"};  
    }  
  
    /** 
     * 添加过滤器Filter 
     */  
    @Override  
    protected Filter[] getServletFilters() {  
        return new Filter[] {  
                new CharacterEncodingFilter("UTF-8", true, true)//spring提供的字符编码过滤器  
            };  
    }  
}  

原理:servlet3.0之后的版本允许动态加载servlet,只是按照规范需要实现ServletContainerInitializer接口。于是spring mvc在自己的包内实现了一个类SpringServletContainerInitializer,它实现了ServletContainerInitializer接口, 这样就能够通过它去加载我们提供的WebAppInitializer类。其中关于Swagger2的配置:

Java代码 

@Configuration  
@EnableSwagger2  
public class Swagger2Config {  
    /** 
     * 创建API应用 
     * appinfo()增加API相关信息 
     * 通过select()函数返回一个ApiSelectorBuilder实例,用来控制那些接口暴露给Swagger来展现 
     * 本例采用置顶扫描的包路径来定义指定要建立API的目录 
     */  
    @Bean  
    public Docket createRestApi() {
        Docket docket = new Docket(DocumentationType.SWAGGER_2)
                .apiInfo(apiInfo())
                .select() // 选择那些路径和api会生成document
                       .apis(RequestHandlerSelectors.basePackage("edu.uestc.avatar.web.controller")) //加了ApiOperation注解的方法,才生成接口文档
               
                .apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class))//这里采用包含注解的方式来确定要显示的接口
                .paths(PathSelectors.any()).build();//PathSelectors.any()对所有路径进行监控
        return docket;
    }
  
  
    /** 
     * 创建改API的基本信息(这些基本信息会展示在文档页面中) 
     * 访问地址: http://项目实际地址/swagger-ui.html 
     */  
    public ApiInfo apiInfo() {  
        return new ApiInfoBuilder()  
                .title("Spring MVC 中使用Swagger2构建RESTful API")  
                .description("此API提供接口测试调用")  
                .termsOfServiceUrl("https://adan-chiu.iteye.com/")  
                .license("License Version 1.0")  
                .licenseUrl("https://adan-chiu.iteye.com/")  
                .version("1.0").build();  
    }  
}  

 控制器添加对接口文档的支持Java代码 

/** 
 * 构建基于RESTful风格的webservice接口 
 */  
@Api(tags = "book webservice 服务")  
@RestController  
public class BookController {  
    @Autowired private BookService service;  
  
    @ApiOperation(httpMethod = "POST", value = "保存图书",consumes = "JSON",produces = "JSON")  
    @PostMapping("/book")  
    public Book save(@RequestBody Book book){  
        return service.save(book);  
    }  
  
    @ApiOperation(value = "根据图书编号加载图书信息",produces = "JSON")  
  
    @GetMapping("/book/{id}")  
    public Book findById(@PathVariable("id") Integer id){  
        return service.find(id);  
    }  
  
    @GetMapping("/book") @ApiOperation(httpMethod = "GET", value = "分页加载图书信息",produces = "JSON")  
    public PageView<Book> find(@RequestParam(defaultValue = "1") Integer currentPage,  
                         @RequestParam(defaultValue = "10") Integer pageSize){  
        return service.list(currentPage,pageSize);  
    }  
  
    @ApiOperation(value = "根据图书编号删除图书信息",produces = "JSON")  
  
    @DeleteMapping("/book/{id}")  
    public Book remove(@PathVariable("id") Integer id){  
        return service.remove(id);  
    }  
  
    @ApiOperation(httpMethod = "PUT", value = "编辑图书信息",consumes = "JSON",produces = "JSON")  
    @PutMapping("/book")  
    public Book edit(@RequestBody Book book){  
        return service.edit(book);  
    }  
}  

 生成文档


 提供测试

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值