SpringMVC | 基础(二)

一. 数据校验

  • JSR 303:是 Java 为 Bean 数据合法性校验提供的标准框架,它已经包含在 JavaEE 6.0 中
  • JSR 303 通过在 Bean 属性上标注类似于 NotNullMax 等标注的注解指定校验规则
  • Hibernate Validator 是 JSR 303 的一个参考实现(注:和hibernate没有任何关系)
1.1 所需架包
  • hibernate-validator-5.4.2.Final.jar
  • jboss-logging-3.3.0.Final.jar
  • validation-api-1.1.0.Final.jar
1.2 步骤

①. 使用 JSR 303 验证标准的 jar 包
②. 加入 hibernate validator 验证框架
③. 在 SpringMVC 配置文件中添加 <mvc:annotation-driven/>
④. 需要在 bean 的属性上添加对应的注解
⑤. 在目标方法 bean 类型的前面添加 @Valid 注解

配置校验文件

<!-- 标准配置 -->
<mvc:annotation-driven></mvc:annotation-driven>

<mvc:annotation-driven/> 会默认装配好一个 LocalValidatorFactoryBean ,因此这里我就直接使用默认的配置

这里我选择三个注解来说明如何使用这个框架

public class Employee {
    @NotEmpty
    private String lastName;

    @Email
    private String email;
    
    @Past
    private Date birth;

通过 BindingResult 来捕获校验

@RequestMapping(value="/emp", method=RequestMethod.POST)
public String save(@Valid Employee employee, BindingResult bindingResult, 
        Map<String,Object> map) {
    System.out.println("save: " + employee);
    
    if(bindingResult.getErrorCount() > 0) {
        System.out.println("出错了!");
        
        for(FieldError error: bindingResult.getFieldErrors()) {
            System.out.println(error.getField() + ": " + error.getDefaultMessage());
        }
        
        //若验证出错, 则转向定制的页面
        map.put("departments", departmentDao.getDepartments());
        return "input";
    }
    
    employeeDao.save(employee);
    return "redirect:/emps";
}

在需要的 POJO 前面加上 @Valid 注解。
BindingResult 必须和 @Valid 注解同时使用,且放在 @Valid 注解后面,是用来存放校验结果的,从中可以获取错误信息

1.3 参考

【SpringMVC学习06】SpringMVC中的数据校验

二. 处理JSON

2.1 加入架包
  • jackson-annotations-2.9.6.jar
  • jackson-core-2.9.6.jar
  • jackson-databind-2.9.6.jar

这里我使用的是 jackon 的处理 JSON 的工具。(注:如果使用的是 Spring4.0,则 jackon 的 jar 包版本至少需要是 2.6 及以上)

2.2 配置转换器

由于使用的是 <mvc:annotation-driven/>,因此不需要我们配置注解驱动,系统已经帮我们配置好了

2.3 代码分析

①.从后台向前台传输JSON数据

后台代码

@ResponseBody
@RequestMapping("/getUsers")
public Map<String, Object> getUser(){
    Map<String, Object> map = new HashMap<>();
    map.put("101", new Employee(1, "luwenhe", "luwenh@123.com", 2, new Department(1, "nihao")));
    map.put("102", "luwenhe2");
    map.put("103", "luwenhe2");
    map.put("104", "luwenhe2");
    map.put("105", "luwenhe2");
    return map;
}

需要加方法前面加上 @ResponseBody 注解,关于 @ResponseBody 的作用后面会加以解释

此时如果直接在地址栏里面输入对应的地址,会直接显示出一串 JSON 格式的数据,结果如下:

从开发者工具里可以看出,确实是传了 JSON 格式的数据

@Response注解的作用:

@responseBody 注解的作用是将 controller 的方法返回的对象通过适当的转换器转换为指定的格式之后,写入到 response 对象的 body 区,通常用来返回 JSON 数据或者是 XML

数据,需要注意的呢,在使用此注解之后不会再走试图处理器,而是直接将数据写入到输入流中,他的效果等同于通过 response 对象输出指定格式的数据。

②. 从前台向后台传输JSON数据

前台代码

$(function(){
        
    var jsonData = {
            "id": 101,
            "lastName": "luwenhe",
            "department": {
            "id": 102,
                "departmentName": "hello"
            }
    }
    
    $.ajax({
        url: '${pageContext.request.contextPath }/getJson',
        type: 'POST',
        contentType:'application/json;charset=utf-8',
        data: JSON.stringify(jsonData),
        success: function(data){
            
        }
    });
        
});

后台代码

@ResponseBody
@RequestMapping("/getJson")
public Employee get(@RequestBody Employee employee) {
    System.out.println(employee);
    return employee;
}

关于 @RequestBody:当请求的格式为 application/json, application/xml等。这些格式的数据,必须使用 @RequestBody 来处理

我们来看一下开发者工具中的结果:


2.4 参考

三. 文件上传

  • SpringMVC 的文件上传是通过即插即用的 MultipartResolver 实现的。
  • Spring 用 Apache Jakarta Commons 的 FileUpload 技术实现了一个 MultipartResolver 的实现类:CommonsMultipartResolver
3.1 加入架包
  • commons-fileupload-1.3.3.jar
  • commons-io-2.6.jar
3.2 配置

因为默认情况下不能处理文件的上传工作,如果要使用,则需要在上下文配置 MultipartResolver

<!-- 配置 MultipartResolver -->
<bean id="multipartResolver" 
    class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
    <property name="defaultEncoding" value="UTF-8"></property>
    <property name="maxUploadSize" value="10240000"></property>
</bean> 

defaultEncoding:必须和用户 JSP 的 pageEncoding 属性一直,以便争取解析表单内容

①. 上传单个文件

前台代码:在表单里别忘了写 enctype="multipart/form-data"

<form action="testFileUpload" method="post" enctype="multipart/form-data">
    File: <input type="file" name="file"/>
    Desc: <input type="text" name="desc"/>
    <input type="submit" value="Submit"/>
</form>

后台代码

public boolean saveFile(MultipartFile file, String path) throws IllegalStateException, IOException {
    if(!file.isEmpty()) {
        File file2 = new File(path);
        if(!file2.exists()) {
            file2.mkdirs();
        }
        String savePath = path + "//" + file.getOriginalFilename();
        
        file.transferTo(new File(savePath));      //将内存中的数据写入磁盘
            return true;
    }   
        
    return false;
}

@RequestMapping("/testFileUpload")
public String testFileUpload(@RequestParam("desc") String desc, 
        @RequestParam("file") MultipartFile file, Model model) throws IOException {
        
    saveFile(file, "E://test1");
    model.addAttribute("desc", desc);
    model.addAttribute("file", file.getOriginalFilename());
    
    return "success";
}

结果


②. 上传多个文件

前台代码

<form action="testFileUpload1" method="post" enctype="multipart/form-data">
    File: <input type="file" name="files"/><br>
    File1: <input type="file" name="files"/><br>
    Desc: <input type="text" name="desc"/>
    <input type="submit" value="Submit"/>
</form>

后台代码

@RequestMapping("/testFileUpload1")
public String testFileUploads(MultipartFile[] files) throws IllegalStateException, IOException {
    if(files != null && files.length > 0) {
        for(int i=0; i<files.length; i++) {
            MultipartFile file = files[i];
            System.out.println(file.getOriginalFilename());
            System.out.println(file.getContentType());
            System.out.println(file.getSize());
            System.out.println("===============================");  
            //写入磁盘,这个方法在上面有写
            saveFile(file, "E://test2");
        }
    }
    
    return "success";
}

结果

上传成功!!!

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

推荐阅读更多精彩内容