(一)第一个项目存在的问题
1、由于show.jsp和index.jsp都存在webapp文件夹下,所以用户可以随意访问这几个文件。用户只要更改地址栏:
http://localhost/ch01_hello_springmvc/show.jsp
那么可以不用发出some.do请求,即可直接跳转到这。但是由于没有发出请求,所以请求数据处是空白的:
2、如何改变现状?
(二)改进的springmvc程序
2.1 项目创建(复制)
1、我们回到项目文件夹,将ch01的项目拷贝一份粘贴到原路径,并改名为ch01 hello springmvc-2。
双击这个项目文件夹,将target文件夹和.iml文件删除:
记事本打开pom.xml文件,改下<artifactId标签为新项目名。
2、找到右上角Project Structure的图标,点击Modules,点击上面的+号,选择Import Module,弹出路径文件夹,找到ch01 hello springmvc-2文件夹,点击OK。选择Import Module from external module,选择Maven,点击Finish。 再点击OK,如果Dependencies那里提示No SDK,就要设置一下JDK;否则就是可以了。
2.2 代码修改及补充
1、WEB-INF目录下的jsp,用户是不能直接访问到的,所以可以在WEB-INF下新建view目录,将show.jsp放到view目录下,同时新建other.jsp。
这是other.jsp中的内容:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<h3>other.jsp从request作用域获取数据</h3><br/>
<h3>msg数据:${msg}</h3>
<h3>fun数据:${fun}</h3>
</body>
</html>
2、然后到MyController中纠正路径:
3、接着发布项目
先点击上方MyTomcat,选择Edit configuration,选择“Deployment”,点击-号删除原有的war包,再点击+号,选择“Artif…”,选择新建的“ch01 hello springmvc-2:war exploder”包,点击ok。然后在Application context处修改名字,变得更简洁一点,点击Apply,再点击OK。
点击启动按钮即可发布。
输入路径:http://localhost:80/ch01_hello_springmvc_2/即可访问。(如果不记得路径可以点击上方MyTomcat,选择Edit configuration,查看URL)
也是成功的!
2.3 配置视图解析器
但是上面的方法补充路径非常繁琐,而且出现other.jsp两个请求展示界面时,很可能牵扯出错。这时我们选择视图解析器,可以只用逻辑名称指定视图。
(1)在springmvc.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:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">
<!--声明组件扫描器-->
<context:component-scan base-package="com.bjpowernode.controller"/>
<!--声明 springmvc框架中的视图解析器,帮助开发人员设置视图文件的路径-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!--前缀:视图文件位置-->
<property name="prefix" value="/WEB-INF/view/"/>
<!--后缀:视图文件的扩展名-->
<property name="suffix" value=".jsp"/>
</bean>
</beans>
(2)回到MyController类中,再写一个doOther方法,可以同时给它分配好几个请求{"/other.do","/second.do"}。
package com.bjpowernode.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
/*
* @Controller:创建处理器对象,对象放在springmvc容器中
*
* 能处理请求的都是控制器(处理器):MyController能处理请求,
* 叫做后端控制器(back controller)
* */
@Controller
public class MyController {
@RequestMapping(value={"/some.do","/first.do"})
public ModelAndView doSome(){
//处理some.do请求,相当于service调用处理完成
ModelAndView mv = new ModelAndView();
//添加数据,框架在请求的最后把数据放入到request作用域
//相当于request.setAttribute("msg","欢迎使用...");
mv.addObject("msg","欢迎使用springmvc做web开发");
mv.addObject("fun","执行的是doSome方法");
mv.setViewName("show");
return mv;
}
@RequestMapping(value={"/other.do","/second.do"})
public ModelAndView doOther(){
ModelAndView mv = new ModelAndView();
mv.addObject("msg","==========欢迎使用springmvc做web开发============");
mv.addObject("fun","执行的是doOther方法");
mv.setViewName("other");
return mv;
}
}
(3)修改一下index.jsp文件
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<p>第一个springmvc项目</p>
<p><a href="some.do">发起some.do的请求</a></p>
<p><a href="other.do">发起other.do的请求</a></p>
</body>
</html>
(4)运行http://localhost:80/ch01_hello_springmvc_2/:
点击超链接:
如果把地址http://localhost/ch01_hello_springmvc_2/other.do改成http://localhost/ch01_hello_springmvc_2/second.do,同样能有效处理请求:
所以,可以通过不同的地址访问同一个方法,也可以在同一个类中创建多个方法处理不同的请求。
第二章 springmvc注解式开发
(一)@RequestMapping写公共模块
1.1 项目创建(复制)
1、按照之前的方法,我们将代码复制一份,改名为ch02 requestmapping,删掉里面的target文件夹和.iml文件。然后记事本打开pom.xml文件,改下<artifactId标签为新项目名。
2、找到右上角Project Structure的图标,点击Modules,点击上面的+号,选择Import Module,弹出路径文件夹,找到ch02 requestmapping文件夹,点击OK。选择Import Module from external module,选择Maven,点击Finish。 再点击OK,如果Dependencies那里提示No SDK,就要设置一下JDK;否则就是可以了。
1.2 代码修改
1、在MyController.java中增加user公共模块,表示以下请求都是在user模块下发起的。
package com.bjpowernode.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
/**
* @RequestMapping:
* 放在类外面的@RequestMapping注解的value:
* 所有请求地址的公共部分,也可以叫模块名称
* 也就是说,下面的some.do请求地址其实是/user/some.do
*/
@Controller
@RequestMapping("/user")
public class MyController {
@RequestMapping(value={"/some.do","/first.do"})
public ModelAndView doSome(){
ModelAndView mv = new ModelAndView();
mv.addObject("msg","欢迎使用springmvc做web开发");
mv.addObject("fun","执行的是doSome方法");
mv.setViewName("show");
return mv;
}
@RequestMapping(value={"/other.do","/second.do"})
public ModelAndView doOther(){
ModelAndView mv = new ModelAndView();
mv.addObject("msg","==========欢迎使用springmvc做web开发============");
mv.addObject("fun","执行的是doOther方法");
mv.setViewName("other");
return mv;
}
}
2、修改一下index.jsp文件
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<p>第一个springmvc项目</p>
<p><a href="user/some.do">发起some.do的请求</a></p>
<p><a href="user/other.do">发起other.do的请求</a></p>
</body>
</html>
3、发布项目
先点击上方MyTomcat,选择Edit configuration,选择“Deployment”,点击-号删除原有的war包,再点击+号,选择“Artif…”,选择新建的“ch02 requestmapping:war exploder”包,点击ok。然后在Application context处修改名字,变得更简洁一点,点击Apply,再点击OK。
点击启动按钮即可发布。
输入路径:http://localhost:80/ch01_hello_springmvc_2/即可访问。(如果不记得路径可以点击上方MyTomcat,选择Edit configuration,查看URL)
也是成功的!
(二)@RequestMapping指定请求方式Method
1、按照之前的方法,我们重新复制了一份项目,并命名为ch02 requestmapping2-POST,并更改了Tomcat的应用的项目。
2、先在MyController中给不同方法设定不同的请求方式Method。
package com.bjpowernode.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;
@Controller
@RequestMapping("/user")
public class MyController {
/**
* @RequestMapping(value = "",method = )
* 属性:method 表示请求的方式,它的值是RequestMethod类枚举值
* get请求方式, method = RequestMethod.GET
* post请求方式,method = RequestMethod.POST
*/
//指定sme.do用GET请求获取
@RequestMapping(value="/some.do",method= RequestMethod.GET)
public ModelAndView doSome(){
ModelAndView mv = new ModelAndView();
mv.addObject("msg","欢迎使用springmvc做web开发");
mv.addObject("fun","执行的是doSome方法");
mv.setViewName("show");
return mv;
}
//指定other.do 用post请求获取
@RequestMapping(value="/other.do",method=RequestMethod.POST)
public ModelAndView doOther(){
ModelAndView mv = new ModelAndView();
mv.addObject("msg","==========欢迎使用springmvc做web开发============");
mv.addObject("fun","执行的是doOther方法");
mv.setViewName("other");
return mv;
}
//不指定请求方式,没有限制
@RequestMapping(value="/first.do")
public ModelAndView doFirst(){
ModelAndView mv = new ModelAndView();
mv.addObject("msg","==========欢迎使用springmvc做web开发============");
mv.addObject("fun","执行的是doFirst方法");
mv.setViewName("other");
return mv;
}
}
3、然后修改下index.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<p>第一个springmvc项目</p>
<p><a href="user/some.do">发起some.do的get请求</a></p>
<br/>
<form action="user/other.do" method="post">
<input type="submit" value="post请求other.do">
</form>
</body>
</html>
使用form表单接收post请求。
4、运行该项目
如果index处some.do和other.do都改成first.do也是可行的,因为first.do不受限。
(三)处理器方法的参数
1、我们还需要接收用户传过来的参数并进行处理,这就涉及到处理器方法传参,这里主要包含四类参数,都是放在处理器方法的形参位置。
分别代表请求、应答、会话、请求参数。
3.1 先说前面三大参数
1、我们在MyController的first.do方法上获取前三种参数,并获取name。
@RequestMapping(value="/first.do")
public ModelAndView doFirst(HttpServletRequest request,
HttpServletResponse response,
HttpSession session){
ModelAndView mv = new ModelAndView();
mv.addObject("msg","==========欢迎使用springmvc做web开发============"+request.getParameter("name"));
mv.addObject("fun","执行的是doFirst方法");
mv.setViewName("other");
return mv;
}
2、index.jsp都改成了first.do,然后重新启动Tomcat,跳转成功后,在浏览器栏的地址后加上name=zhangsan。即:http://localhost/ch02_requestmapping2/user/first.do?name=zhangsan
成功获取了!
3、第四大参数主要是用来获取用户提交的姓名、性别等属性值的,接下来我们将讲解两种接收方式:逐个参数接收、对象参数接收。
3.2 接收参数-逐个接收
1、按照之前的方法,我们重新复制了一份项目,并命名为ch03 recevieparam,并更改了Tomcat的应用的项目。
2、先更改index.jsp,提交请求页面。
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<p>提交参数给Controller</p>
<form action="receiveproperty.do" method="post">
姓名:<input type="text" name="name"><br/>
年龄:<input type="text" name="age"><br/>
<input type="submit" value="提交参数">
</form>
</body>
</html>
3、更改MyController页面,映射请求为"/receiveproperty.do",传入形参name和age:
@Controller
public class MyController {
/**
*逐个接收请求参数:
* 要求:处理器(控制器)方法的形参名和请求中参数名必须一致。比如index.jsp中name属性对应的是name和age,那么doSome方法的形参中就得传入name和age。
* 同名的请求参数赋值给同名的形参
*框架接收请求参数:
* 1 使用request对象接收请求参数
* String strName = request.getParameter("name");
* String strAge = request.getParameter("age");
* 2 springmvc框架通过dispatcherServlet 调用MyController的doSome方法
* 调用方法时,按名称对应,把接收的参数赋值给形参 doSome(strName,Integer.valueOf(strAge))
* 框架会提供类型转换的功能,把String转换为 int ,long ,float ,double等
*
*/
@RequestMapping(value="/receiveproperty.do")
public ModelAndView doSome(String name,Integer age){
//System.out.println("doSome,name="+name+"+ age="+age);
//可以在方法中直接使用name,age
ModelAndView mv = new ModelAndView();
mv.addObject("myname",name);
mv.addObject("myage",age);
mv.setViewName("show");
return mv;
}
}
4、更改展示页面show.jsp:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<h3>show.jsp从request作用域获取数据</h3><br/>
<h3>myname数据:${myname}</h3>
<h3>myage数据:${myage}</h3>
</body>
</html>
5、运行成功后:
可以看到这里能成功获取用户提交的参数值(如果age为空值或整数值都能正常显示,但是为abc这样的就报错400):
但是如果用户提交的数据中有中文,那么会出现乱码的情况(但是如果将index.jsp页面中的method属性值改为get就不会乱码):
怎么解决呢?
在提交请求参数时,get请求方式中文没有乱码。使用post方式提交请求,中文有乱码,需要使用过滤器处理乱码的问题。
3.3 过滤器解决中文乱码问题
1、只需要在WEB-INF下面的web.xml文件添加过滤器代码:
<!--注册声明过滤器,解决post请求乱码的问题-->
<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>
<!--强制请求对象(HttpServletRequest)使用encoding编码的值-->
<init-param>
<param-name>forceRequestEncoding</param-name>
<param-value>true</param-value>
</init-param>
<!--强制应答对象(HttpServletResponse)-->
<init-param>
<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>
2、至于在<filter标签里面怎么设置<init-param,可以选中CharacterEncodingFilter,然后ctrl+左键单击进入函数:
可以看到我们要设置的参数有encoding、forceRequestEncoding、forceResponseEncoding三个,并且后面两个参数一开始都设置为false,需要手动改成true。
3、点击Run运行:
(四)总结
1、SpringMVC概述:
2、SpringMVC的MVC组件
请求request交给前端控制器(也就是中央处理器DispatcherServlet),前端控制器并不处理请求,而是转发给Controller,处理完之后将结果放到ModelAndView。Model指的是数据,View是视图,view是显示结果的(显示Model数据的)。
总而言之,C代表控制器,有两个(分别是前端控制器即DispatcherServlet和后端控制器即文中MyController),M是数据,V是显示结果的视图。
3、复习之前的学习内容
(五)解决请求中参数名和处理器方法的形参名不一致–@RequestMapping注解
1、修改首页index.jsp,增加一个表单:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<p>提交参数给Controller</p>
<form action="receiveproperty.do" method="post">
姓名:<input type="text" name="name"><br/>
年龄:<input type="text" name="age"><br/>
<input type="submit" value="提交参数">
</form>
<p>请求参数名和处理器方法的形参名不一样</p>
<form action="receiveParam.do" method="post">
姓名:<input type="text" name="rname"><br/>
年龄:<input type="text" name="rage"><br/>
<input type="submit" value="提交参数">
</form>
</body>
</html>
2、在MyController类中增加映射"/receiveParam.do",并写这个方法,上面的处理器形参名可以是name,但是要用@RequestParam标签指定请求中的参数名其实是rname;另外,由于这个注解函数里面默认了required的值为true,也就是说这个属性必填,否则就报400错误,如果可以不填需设置该属性为false。
在MyController中添加代码:
/*
* 解决请求中参数名和处理器方法的形参名不一样问题
* @RequestParam:定义在处理器方法的形参前面
* 属性:1. value,请求参数名,可省略
* 2. required,是一个Boolean类型,默认为true,表示必须包含参数
* */
@RequestMapping(value = "/receiveParam.do")
public ModelAndView receiveParam(@RequestParam(value = "rname",required = false) String name,
@RequestParam(value = "rage",required = false) Integer age){
//System.out.println("doOther方法的,name="+name+", age="+age);
ModelAndView mv = new ModelAndView();
mv.addObject("myname",name);
mv.addObject("myage",age);
mv.setViewName("show");
return mv;
}
3、运行成功: