SpringMVC + JSON构建基于RESTful风格的服务器 备忘

§环境构筑

可以选择用maven新建工程再导入到ide中,也可以直接在ide中新建maven应用。

这里选择后者。下载安装eclipse javaEE版本、maven和Tomcat。

exlipse可以直接安装maven插件,网址是http://m2eclipse.sonatype.org/sites/m2e

新建Maven Project,搭建web工程,注意选择maven-archetype-webapp类型。

GroupID是项目组织唯一的标识符,实际对应JAVA的包的结构,是main目录里java的目录结构。
ArtifactID就是项目的唯一的标识符,实际对应项目的名称,就是项目根目录的名称。

创建项目后修改项目Project Facets -> Dynamic web Module版本为2.5
http://www.cnblogs.com/shangxiaofei/p/5447150.html

新建maven工程后在pom.xml中添加所需的库。一般包括spring有关的jar包以及jackson(封装了json相关的功能,也有教程说需要commons-*,暂时没用到),其他库如有需要在进行添加。简单的方法是:打开pom.xml的Dependencies页面,选择add在搜索相应库就可以了。当然从网上直接copy所有依赖项更简单。

再为工程绑定Tomcat服务器。

§配置

  • 先配置WEB-INF/web.xml,注意
<servlet-mapping>  
    <servlet-name>mvc-dispatcher</servlet-name>  
    <url-pattern>/</url-pattern>  
</servlet-mapping>  

这个标签是实现RESTful风格开发所必须的,即对所有Action请求路径作出修改。

  • 再配置WEB-INF/mvc-dispatcher-servlet.xml,注意

    <mvc:annotation-driven />

    这个标签注册了Spring MVC分发请求到控制器所必须的DefaultAnnotationHandlerMapping和AnnotationMethodHandlerAdapter实例。保证了@Controll注解的前提配置,同时注意在<bean>头中添加相关地址,否则会出错。

    xmlns:mvc="http://www.springframework.org/schema/mvc"

    注意返回的jsp文件路径,这个没那么重要了,只要不出错就行。

  • 配置applicationContext.xml,目前还不清楚有什么用。

数据的接收与处理

添加controller包以及实现类BaseController(包名称WEB-INF/mvc-dispatcher-servlet.xml中有设置)。

@Controller

public class BaseController { 
    
    /*@RequestMapping(value="/fruit", method = POST)
        这是对RESTful风格请求映射的注解,默认是不区分GET还是POST等方法的,
        如果需要限定再增加method=相应方法。*/
    @RequestMapping("/index")  
    public String index() {  
        return "index";  
    }  

    @RequestMapping(value="/jsonfeed")  
    /*@ResponseBody用于将Controller的方法返回的对象,
    通过适当的HttpMessageConverter转换为指定格式后,
    写入到Response对象的body数据区。并不需要我们手动处理。
    使用时机:
    返回的数据不是html标签的页面,而是其他某种格式的数据时(如json、xml等)使用*/
    public @ResponseBody MyJson getJSON() {  
        System.out.println("Your Message : ");
        MyJson json = new MyJson();
        json.setResult(1);
        json.setInfo("apple");
        return json;
    }

    @RequestMapping(value="/fruit", method = POST)
    public @ResponseBody Fruits getFruit(@RequestBody Fruits fr) {
        System.out.println("Your Message : "+fr);
        Fruits fruit = new Fruits();
        fruit.setNumber(fr.getNumber());
        fruit.setFruit(fr.getFruit());
        fruit.setStatus(1);
        return fruit;
    }   
}

@RequestMapping和@ResponseBody注解的作用都写在注释里,这里主要再说一下@RequestBody注解。

一般客户端发送POST请求的的请求都会写在header里的body里,通常使用JSON.stringify()转换成成字符串了,所以服务器在处理post请求时使用@PathVariable注解时并不能直接拿到请求数据的属性,但是好像可以用@RequestParam注解获取数据(需要其他依赖),这里我还不是很清楚,有待进一步探究。我在遇到这个问题时首先想到的方法是将字符串转换成java中的Map、List或者对象等数据结构。因此,我创建了Fruits
对象:

public class Fruits {
    private int number;
    private String fruit;
    private int status;
    
    public int getNumber() {
        return number;
    }
    public void setNumber(int name) {
        number = name;
    }
    
    public String getFruit() {
        return fruit;
    }
    public void setFruit(String name) {
        fruit = name;
    }
    
    public int getStatus() {
        return status;
    }
    public void setStatus(int name) {
        status = name;
    }
}

框架会自动帮我转换JSON和对象。这样基于RESTful风格的Spring MVC web服务器就创建成功了。下一步准备调查如何传送文件。

客户端我是用React Native写的,其中POST请求的API使用的fetch。


续 文件上传服务

项目要求新增文件上传功能,在原有项目基础上对应了一下。
这个教程不错:http://www.yiibai.com/spring_mvc/spring-mvc-file-upload-tutorial.html

主要是在pom.xml添加commons.io和commons.fileupload依赖,在mvc-dispatcher-servlet里加入multipartResolver的配置,包括上传文件大小的限制等等。

由于客户端上传文件是放在表单里的,所以这里要对应一下,@RequesParam("files")中的files是表单中自己设置的属性。

最后贴出所有xml文件和处理文件上传的controller吧。

pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.psh</groupId>
  <artifactId>xxxDemoServer</artifactId>
  <packaging>war</packaging>
  <version>0.0.1-SNAPSHOT</version>
  <name>xxxDemoServer Maven Webapp</name>
  <url>http://maven.apache.org</url>
  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>3.8.1</version>
      <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-web</artifactId>
        <version>4.3.9.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc</artifactId>
        <version>4.3.9.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-beans</artifactId>
        <version>4.3.9.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-expression</artifactId>
        <version>4.3.9.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-core</artifactId>
        <version>4.3.9.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-aop</artifactId>
        <version>4.3.9.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>4.3.9.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>javax.servlet-api</artifactId>
        <version>3.0.1</version>
    </dependency>
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-core</artifactId>
        <version>2.9.1</version>
    </dependency>
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-annotations</artifactId>
        <version>2.9.1</version>
    </dependency>
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-databind</artifactId>
        <version>2.9.1</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/commons-fileupload/commons-fileupload -->
    <dependency>
        <groupId>commons-fileupload</groupId>
        <artifactId>commons-fileupload</artifactId>
        <version>1.3.2</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/commons-io/commons-io -->
    <dependency>
        <groupId>commons-io</groupId>
        <artifactId>commons-io</artifactId>
        <version>2.5</version>
    </dependency>
  </dependencies>
  <build>
    <finalName>xxxDemoServer</finalName>
  </build>
</project>

web.xml

<?xml version="1.0" encoding="UTF-8"?>  
<web-app version="2.5"  
    xmlns="http://java.sun.com/xml/ns/javaee"  
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee  
    http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">  
      
  <display-name>xxxDemoServer</display-name>  
  <!-- 字符集 过滤器  -->  
    <filter>  
        <filter-name>CharacterEncodingFilter</filter-name>  
        <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>  
        <init-param>  
            <param-name>encoding</param-name>  
            <param-value>UTF-8</param-value>  
        </init-param>  
        <init-param>  
            <param-name>forceEncoding</param-name>  
            <param-value>true</param-value>  
        </init-param>  
    </filter>  
    <filter-mapping>  
        <filter-name>CharacterEncodingFilter</filter-name>  
        <url-pattern>/*</url-pattern>  
    </filter-mapping>  
    <!-- Sping View分发器 -->
    <servlet>
        <servlet-name>mvc-dispatcher</servlet-name>
        <servlet-class>
                        org.springframework.web.servlet.DispatcherServlet
                </servlet-class>
         <init-param>  
            <param-name>contextConfigLocation</param-name>  
            <param-value>/WEB-INF/mvc-dispatcher-servlet.xml</param-value>  
        </init-param>  
        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>mvc-dispatcher</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>
    
    <listener>
        <listener-class>
            org.springframework.web.context.ContextLoaderListener
        </listener-class>
    </listener>
</web-app> 

applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="http://www.springframework.org/schema/beans 
       http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
       http://www.springframework.org/schema/context 
       http://www.springframework.org/schema/context/spring-context-3.0.xsd
       http://www.springframework.org/schema/tx 
       http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
       http://www.springframework.org/schema/aop
       http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
    
    <!-- 扫描类包,将标注Spring注解的类自动转化Bean,同时完成Bean的注入 -->
    <context:component-scan base-package="com.psh.controller"/>
    
</beans>

BaseController.java片段

@RequestMapping(value="/upload/audio", method = POST)
public @ResponseBody Fruits saveAudio(HttpServletRequest request,
                                    @RequestParam("files") MultipartFile[] files) {
    System.out.println("Your Message got ");
    
    // Root Directory.
    String uploadRootPath = request.getServletContext().getRealPath(
            "upload");
    System.out.println("uploadRootPath=" + uploadRootPath);

    File uploadRootDir = new File(uploadRootPath);
    //
    // Create directory if it not exists.
    if (!uploadRootDir.exists()) {
        uploadRootDir.mkdirs();
    }
    //
    List<File> uploadedFiles = new ArrayList<File>();
    for (int i = 0; i < files.length; i++) {
        MultipartFile file = files[i];

        // Client File Name
        String name = file.getOriginalFilename();
        System.out.println("Client File Name = " + name);

        if (name != null && name.length() > 0) {
            try {
                byte[] bytes = file.getBytes();

                // Create the file on server
                File serverFile = new File(uploadRootDir.getAbsolutePath()
                        + File.separator + name);

                // Stream to write data to file in server.
                BufferedOutputStream stream = new BufferedOutputStream(
                        new FileOutputStream(serverFile));
                stream.write(bytes);
                stream.close();
                //
                uploadedFiles.add(serverFile);
                System.out.println("Write file: " + serverFile);
            } catch (Exception e) {
                System.out.println("Error Write file: " + name);
            }
        }
    }
    
    Fruits fruit = new Fruits();
    fruit.setNumber(1);
    fruit.setFruit("pineapple");
    fruit.setStatus(1);
    return fruit;
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,904评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,581评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,527评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,463评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,546评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,572评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,582评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,330评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,776评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,087评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,257评论 1 344
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,923评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,571评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,192评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,436评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,145评论 2 366
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,127评论 2 352

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,647评论 18 139
  • Spring Boot 参考指南 介绍 转载自:https://www.gitbook.com/book/qbgb...
    毛宇鹏阅读 46,799评论 6 342
  • spring官方文档:http://docs.spring.io/spring/docs/current/spri...
    牛马风情阅读 1,661评论 0 3
  • 《麦田守望者》是捷罗姆·大卫·塞林格创作的一部长篇小说。 该小说讲述了一个16岁少年霍尔顿·考尔菲德,在圣诞节假前...
    礼拜五兰阅读 397评论 9 7
  • 当我开始写这个题目时,我的眼里已经泛起了晶莹。因为它启封了我一段不敢回念的记忆。 今天很偶然的看一个小视频,听到了...
    不修边幅阅读 398评论 0 0