SpringMVC入门学习(二)

ssm框架 springMVC 

在上一篇博客中,我简单介绍了一下SpringMVC的环境配置,和简单的使用,今天我们将进一步的学习下Springmvc的操作。

model.addAttribute()的使用

model接口的源代码:

由图可知,在addAttribute()中有两种入参方式,一种是指明名字var1,一种是不指明名字var1。在不指明名字中,会通过相近的去寻找。

在addAttribute()中,我们可以放任何对象:

首先先导入jsp标签maven相关的库

<!--servlet导入-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
<scope>provided</scope>
</dependency>
<!--标签库的导入-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>

controller里面的代码

@RequestMapping("bye")
public String bye(Model model){
// 放list
List<String> byeList = new ArrayList<>();
byeList.add("小明");
byeList.add("小红");
byeList.add("小方");
model.addAttribute("byeList",byeList);
// 放Map
Map<String,String> map= new HashMap<>();
map.put("one","第一个");
map.put("two","第二个");
map.put("three","第三个");
map.put("four","第四个");
model.addAttribute("map",map);
// 放对象bean
User user = new User();
user.setAge("18");
user.setName("帅哥");
model.addAttribute("user",user); return "bye";
}

jsp里面的使用

放List <br>
<c:forEach items="${byeList}" var="bye">
${bye}<br>
</c:forEach> 放map <br>
${map.one}<br>
${map.two}<br>
${map.three}<br>
${map.four}<br> 放对象bean <br>
${user.age} <br>
${user.name} <br>

转发与重定向

这位博主的例子写的挺好的博客地址

假设你去办理某个执照,

重定向:你先去了A局,A局的人说:“这个事情不归我们管,去B局”,然后,你就从A退了出来,自己乘车去了B局。

转发:你先去了A局,A局看了以后,知道这个事情其实应该B局来管,但是他没有把你退回来,而是让你坐一会儿,自己到后面办公室联系了B的人,让他们办好后,送了过来。

  • 转发forward:
    服务器内部的操作,服务器去请求目标地址的URL【同一个WEB下面的组件】,然后读取返回结果,并将其发送给浏览器。所以在客户端看来,地址栏是没有变化的。
    【转发页面和转发到的页面能够共享数据
  • 重定向redirect:
    重定向是客户端的操作,服务器告诉浏览器要去哪个网址,然后浏览器进行跳转,然后浏览器的地址栏就是跳转的网址。
    不能共享数据

重定向

  1. 不带参数的重定向

    /**
    * 不带重定向到请求网址
    * @param model
    * @return 重定向的网址: /bye
    */
    @RequestMapping("redirect0")
    public String redirect1(Model model){
    return "redirect:/bye";
    }
  2. 带参数的重定向
    (1)使用addAttribute进行字符串拼接

    /**
    * 带参数
    * @param attributes
    * @return 请求的网址是: /mian1?name=bird
    */
    @RequestMapping("redirect1")
    public String redirect1(RedirectAttributes attributes){
    attributes.addAttribute("name","bird");
    return "redirect:main1";
    }

    controller写法:

    @RequestMapping("main1")
    public String main1(@RequestParam("name") String name, Model model){
    //通@RequestParam过获得name数据 model.addAttribute("name",name);
    return "redirect";
    }

    (2)使用addFlashAttribute

    /***
    *
    *
    */
    @RequestMapping("redirect2")
    public String redirect2(RedirectAttributes attributes){
    /*
    * 此时请求的网址是:/mian2
    * addFlashAttribute()是将数据放在session里面,但是session在页面跳转时,会马上移除。
    */
    attributes.addFlashAttribute("name","xiaohuiFlash");
    return "redirect:main2";
    }

    controller的写法:

    /* 与addAttribute不同的是,他是通过@ModelAttribute获得数据
    *
    */
    @RequestMapping("main2")
    public String main2(@ModelAttribute("name") String name, Model model){
    model.addAttribute("name",name);
    return "redirect";
    }

转发

在Springmvc中请求是默认转发到jsp中的【可以省略forward】,例如:

@RequestMapping("hello")
public String hello(Model model){
model.addAttribute("hello","世界");
return "hello";
}

此时是自动转发到:/WEB-INF/jsp/hello.jsp【路径设置问题在上一篇提到过】,当然如果文件不在jsp文件夹中,则可以指令路径,如:return "forward:WEB-INF/index/index.jsp"

如果要转发到controller上,则必须加上forward:

@RequestMapping("hello")
public String hello(Model model){
model.addAttribute("hello","世界");
// 转发到:/bye 的controller上面
return "forward:bye";
}

关于请求路径的问题

在Springmvc中支持ant风格的路径,其中ANT通配符有三种:

通配符 说明
? 匹配任意一个字符【不能为空,不能为/】
* 匹配0个或则任意个字符
** 匹配0或则多个目录

例子:

URL路径 说明
/index?/get 可以为/index1/get,/index2/get,但是不能为/index/get
/index*/get 可以为/index1/get,/indexa1/get,也可以为/index/get
/index/**/get 可以为/index/one/get,/index/one/two/get,也可以为/index/get

其中,会根据最长匹配原则(has more characters)来进行匹配,例如:

/jsp/index/.jsp和/jsp/**/.jsp会优先匹配第一个

Springmvc设置字符编码过滤器

在web.xml的配置文件中:

<!-- characterEncodingFilter字符编码过滤器 -->
<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>
<!--是否强制设置request的编码为encoding,即UTF-8,默认为false -->
<param-name>forceRequestEncoding</param-name>
<param-value>false</param-value>
</init-param>
<init-param>
<!--是否强制设置response的编码为encoding,即UTF-8 -->
<param-name>forceResponseEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter> <filter-mapping>
<filter-name>characterEncodingFilter</filter-name>
<!-- 这里必须写 /* -->
<url-pattern>/*</url-pattern>
</filter-mapping>

注意:此时是设置默认的编码方式,也即是说,可以在自己写的代码中重新指令编码方式。

关于静态资源放行的问题

由于我们经Servlet设置的URI匹配模式是:/,所以,它将静态资源js,css等等也当成了一个后台请求从而导致404错误。

最简单的解决方法,在Spring配置文件中

<!-- 他将在Spring上下文中定义一个DefaultServletHttpRequestHandler来处理静态资源,实际上就是将转发给默认的servlet -->
<mvc:default-servlet-handler/>

但是此时会发现又会出现一个问题,那就是@RequestMapping("/path")不能访问,这时候再配置文件中再添加一句代码

<!-- 原因是因为当没有mvc:default-servlet-handler时,框架默认注册AnnotationMethodHandlerAdapter可以处理@RequestMapping,而当加入时,就没有了,这时候加入mvc:annotation-driven就会注册一个AnnotationMethodHandlerAdapter -->
<mvc:annotation-driven/>

关于form表单提交数据的方式

  • 方式一:直接将表单参数卸载Controller相应的方法的形参中。
    前端表单

    <form action="/form" method="post">
    <input type="text" name="name"><br>
    <input type="password" name="pwd"><br>
    <input type="submit" value="提交">
    </form>
    @RequestMapping("/form")
    后端接受数据
    public String getForm(String name,String pwd){
    /**
    * 在形参中,name和pwd要一一对应
    * @param name
    * @param pwd
    * @return
    */
    System.out.println("名字:"+name);
    System.out.println("密码:"+pwd);
    return "";
    }
  • 方式二:使用HttpServletRequest接受数据

    @RequestMapping("/form")
    public String getForm(HttpServletRequest request){
    System.out.println("名字是"+request.getParameter("name"));
    System.out.println("密码是"+request.getParameter("pwd"));
    return "";
    }
  • 通过一个Bean来接受数据【适合大量数据的情况】
    建立一个UserBean

    public class User {
    private String name;
    private String pwd; public String getName() {
    return name;
    } public void setName(String name) {
    this.name = name;
    } public String getPwd() {
    return pwd;
    } public void setPwd(String pwd) {
    this.pwd = pwd;
    }
    }

    这时候就可将形参改为User了,注意User必须保留默认的构造方法

    @RequestMapping("/form")
    public String getForm(User user){
    System.out.println("名字是"+user.getName());
    System.out.println("密码是"+user.getPwd());
    return "";
    }
  • 使用注解@RequestParam绑定请求参数到方法入参

    @RequestMapping("/form")
    public String getForm(@RequestParam("name")String name,@RequestParam(value = "pwd")String pwd){
    System.out.println("名字是"+name);
    System.out.println("密码是"+pwd);
    return "";
    }

    当然这时候,如果请求的数据没有pwd,比如说请求的数据是:/form?name=one,那么程序便会报错

    13-Nov-2018 02:00:11.459 警告 [http-nio-8080-exec-9] org.springframework.web.servlet.handler.AbstractHandlerExceptionResolver.resolveException Resolved [org.springframework.web.bind.MissingServletRequestParameterException: Required String parameter 'pwd' is not present]

    这时候可以设置@RequestParam的属性required为false

    //此时要将value补上,同时可以设置defaultValue 也就是默认值
    @RequestParam(value = "name",required=false) @RequestParam(value = "name",required=false,defaultValue="0")String name
  • 使用@PathVariable获得路径的参数

    @RequestMapping("/form1/{name}/{pwd}")
    public String form1(@PathVariable String name,@PathVariable String pwd){
    System.out.println("使用@");
    System.out.println("名字是"+name);
    System.out.println("密码是"+pwd);
    return "";
    }

    这时候如果访问http://localhost:8080/form1/one/two使,那么one将绑定在name上,two将绑定在pwd上面。

    输出结果:

    名字是one
    密码是two

关于时间日期提交的问题

当我们的数据库中含有Data类型的数据时,因为form表单提交的是String类型,而在SpringMVC中无法自动的将String类型的转为Data类型,从而无法将数据写入实体类和数据库。解决方法如下:

  • 使用@DateTimeFormat注解

    // 实体类UserDate,在Date上面加上注解
    @DateTimeFormat(pattern = "yyyy-MM-dd")
    private Date date;

    Controller类不需要有任何变化

    @RequestMapping("/formData")
    public String formData(UserDate userData) {
    return "";
    }
  • 使用@InitBinder注解
    @InitBinder用于在@Controller中标注于方法,表示为当前控制器注册一个属性编辑器或者其他,只对当前的Controller有效。

    // 这个方法会在控制器中其他方法之前调用,这样就可以预先处理数据
    @InitBinder
    public void InitBinder(WebDataBinder binder){
    DateFormat format = new SimpleDateFormat("yyyy-MM-dd");
    // 第二个参数表示是否允许为空
    CustomDateEditor dateEditor = new CustomDateEditor(format,true);
    //注册自定义的日期转换格式
    binder.registerCustomEditor(Date.class,dateEditor);
    }

天地有正气,杂然赋流形。下则为河岳,上则为日星。于人曰浩然,沛乎塞苍冥。

最新文章

  1. Linux字符界面下用户账户的设置
  2. 解决32位plsql客户端连接不64位Oracle11g上数据库
  3. mysql日期加减问题
  4. Python的设计模式学习
  5. hdu-1010 dfs+剪枝
  6. C# TextBox中的Validating与Validated事件[转]
  7. Java多线程——创建线程的两种方式
  8. python利用jieba进行中文分词去停用词
  9. Vue2学习(3)
  10. 在kerberos认证过程中Active Directory的作用
  11. 【COCOS2DX-游戏开发之三一】之 坐标系(下) convertToNodeSpace和convertToWorldSpace
  12. 未能加载文件或程序集“Oracle.DataAccess”或它的某一个 依赖项。如何解决?
  13. LA3485 Bridge
  14. MATLAB相关快捷键以及常用函数
  15. 第一天---关于环境和java基础
  16. Swift编程语言学习1.7——断言
  17. 与IE的战斗
  18. 2018/04/01 每日一个Linux命令 之 sleep
  19. JAVA 泛型通配符 ? EXTENDS SUPER 的用法
  20. Thinking in java note1

热门文章

  1. SQL学习(一.索引)
  2. atom编辑器使用“apm install”无法响应的解决方案
  3. Linux环境下java开发环境搭建二 tomcat搭建
  4. java中random的几个方法的使用Math.random()和random().
  5. sass基础常用指南
  6. collection管理程序中不同类别的资源
  7. 【慕课网实战】一、以慕课网日志分析为例 进入大数据 Spark SQL 的世界
  8. springBoot基础2
  9. attempt to open datawindow failed@安装两个PB软件
  10. 「PKUWC2018」随机游走(min-max容斥+FWT)