springMVC摘要
主要学习了springMVC的工作流程(由前端控制器接到用户请求,将请求交给适配器找到合适的处理器进行处理,处理器
将处理结果交给视图解析器处理,再交给jsp页面,最后经过渲染形成需要的HTML页面)
前端控制器–处理器适配器(适配请求)–处理器适配器(调用合适的处理器)–处理器(后端控制器)–视图解析器(渲染生成)–HTML页面
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsICM38FdsYkRGZkRG9lcvx2bjxiNx8VZ6l2cs0TP35EMRpnT1UEVOBDOsJGcohVYsR2MMBjVtJWd0ckW65UbM5WOHJWa5kHT20ESjBjUIF2X0hXZ0xCMx81dvRWYoNHLrdEZwZ1Rh5WNXp1bwNjW1ZUba9VZwlHdssmch1mclRXY39CXldWYtlWPzNXZj9mcw1ycz9WL49zZuBnLzYzMxQDO0ETM5EjNwAjMwIzLc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.png)
根据工作流程配置相应的处理器
组件扫描器,扫描标注有controller的类,然后交给处理器进行处理
前端控制器(负责控制请求,在web.xml中配置)
后端控制器(也即处理器,处理用户请求,在springMVC.xml中配置.)
<!-- 配置注解式(处理器)映射器 -->
<bean
class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping" />
对类中标记了@ResquestMapping的方法进行映射
@Controller
public class UpLoadController {
@RequestMapping("/upload.action")
public String upload(String username,String password,MultipartFile fileName,Model model) throws IllegalStateException, IOException{
System.out.println(username);
System.out.println(password);
<!-- 配置处理器适配器 -->
<bean
class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter" />
直接配置处理器映射器和处理器适配器比较麻烦,可以使用注解驱动来加载。替代注解处理器和适配器的配置。
<!-- 注解驱动 -->
<mvc:annotation-driven />
<!-- 配置视图解析器 -->
<bean
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!-- 配置逻辑视图的前缀 -->
<property name="prefix" value="/WEB-INF/jsp/" />
<!-- 配置逻辑视图的后缀 -->
<property name="suffix" value=".jsp" />
</bean>
除了上述处理器外,还包括异常处理器, 拦截器
系统的dao、service、controller出现异常(预期异常和运行时异常)都通过throws Exception向上抛出,最后由springmvc前端控制器交由异常处理器进行异常处理
配置 异常处理器
在springmvc.xml中添加:
<!-- 配置全局异常处理器 -->
<bean
id="customHandleException" class="cn.self.ssm.exception.CustomHandleException"/>
配置拦截器
作用: 用于对处理器对请求进行预处理和后处理。(比如登录页面判断用户名密码等是否正确,是否为空等,放行还是跳转)
在springmvc.xml中配置拦截器
<!-- 先自定义拦截器,再配置拦截器 -->
<mvc:interceptors>
<mvc:interceptor>
<!-- 所有的请求都进入拦截器 -->
<mvc:mapping path="/**" />
<!-- 配置具体的拦截器 -->
<bean class="cn.self.ssm.interceptor.HandlerInterceptor1" />
</mvc:interceptor>
<mvc:interceptor>
<!-- 所有的请求都进入拦截器 -->
<mvc:mapping path="/**" />
<!-- 配置具体的拦截器 -->
<bean class="cn.self.ssm.interceptor.HandlerInterceptor2" />
</mvc:interceptor>
</mvc:interceptors>
@Service
public class ItemServiceImpl implements ItemService {
@Autowired 将类当做属性注入,然后调用其中的方法
private ItemMapper itemMapper;
@Override
public List<Item> queryItemList() {
// 从数据库查询商品数据
List<Item> list = this.itemMapper.selectByExample(null);
return list;
}
}
@Controller
public class ItemController {
@Autowired
private ItemService itemService;
@RequestMapping("/itemList") //或者@RequestMapping(value="item")
public ModelAndView queryItemList() {
// 获取商品数据
List<Item> list = this.itemService.queryItemList();
ModelAndView modelAndView = new ModelAndView();
// 把商品数据放到模型中
modelAndView.addObject("itemList", list);
// 设置逻辑视图
modelAndView.setViewName("itemList");
return modelAndView;
@RequestMapping定义不同的处理器映射规则
@RequestMapping(value = { "itemList", "itemListAll" })
public ModelAndView queryItemList()
//可以将多个url映射到同一个方法
请求方法限定
@RequestMapping(method = RequestMethod.GET)
@RequestMapping(value = "itemList",method = RequestMethod.POST)
@RequestMapping(method = {RequestMethod.GET,RequestMethod.POST})
请求中的参数绑定问题
简单参数绑定
页面点击修改按钮,发起请求
http://127.0.0.1:8080/springmvc-web/itemEdit.action?id=1
一.
RequestMapping("/itemEdit")
public ModelAndView queryItemById(HttpServletRequest request) {
(支持的参数类型:
1.通过request对象获取请求信息
2.通过response处理响应信息
3.通过session对象得到session中存放的对象)
// 从request中获取请求参数
String strId = request.getParameter("id");
Integer id = Integer.valueOf(strId);
// 根据id查询商品数据
Item item = this.itemService.queryItemById(id);
二.绑定简单类型
1.(当请求的参数名称和处理器形参名称一致时会将请求参数与形参进行绑定,支持的数据类型<推荐使用包装数据类型,基础数据类型不可以为null>包括
整形:Integer、int
字符串:String
单精度:Float、float
双精度:Double、double
布尔型:Boolean、boolean
)
@RequestMapping("/itemEdit")
public String queryItemById(int id, ModelMap model) {
// 根据id查询商品数据
Item item = this.itemService.queryItemById(id);
[email protected]也常用于处理简单类型的绑定(当请求参数名字不对应的时候)。
@RequestMapping("/itemEdit")
public String queryItemById(@RequestParam(value = "itemId", required = true, defaultValue = "1") Integer id,ModelMap modelMap) {
// 根据id查询商品数据
Item item = this.itemService.queryItemById(id);
(参数名字,参数是否必须,参数的,默认值)
3.使用pojo接收表单数据
如果提交的参数很多,或者提交的表单中的内容很多的时候,可以使用简单类型接受数据,也可以使用pojo接收数据(pojo对象中的属性名和表单中input的name属性一致)
@RequestMapping("/updateItem")
public String updateItem(Item item) {
// 调用服务更新商品
this.itemService.updateItemById(item);
// 返回逻辑视图
return "success";
}
4.使用包装的pojo接收查询参数,最后将查询结果返回jsp页面
包装对象定义如下:
public class QueryVo {
private Item item;
set/get
}
接收查询条件
// 绑定包装数据类型
@RequestMapping("/queryItem")
public String queryItem(QueryVo queryVo) {
System.out.println(queryVo.getItem().getId());
System.out.println(queryVo.getItem().getName());
return "success";
高级参数绑定问题
1.绑定数组
功能要求商品列表页面中的每个商品前有一个checkbok,选中多个商品后点击删除按钮把商品id传递给Controller,根据商品id删除商品信息。
前面用pojo的包装类接收了表单数据
public class QueryVo{
private Item item;
private Integer[] ids;
}
我们将查询参数使用item接收,将查询到的结果在页面显示, 然后每个商品前有复选框,当点击复选框则会将
商品的id属性传入到ids属性中根据,然后可根据数组中的id删除相应的商品
@RequestMapping("queryItem")
public String queryItem(QueryVo queryVo, Integer[] ids) {
System.out.println(queryVo.getItem().getId());
System.out.println(queryVo.getItem().getName());
System.out.println(queryVo.getIds().length);
System.out.println(ids.length);
return "success";
}
//未做删除操作
2.绑定list集合
需求
<1>在商品列表页面中可以对商品信息进行修改。
<2>可以批量提交修改后的商品数据。
public class QueryVo{
private Item item;
private Integer[] ids; //可以选择哪些进行批量修改
private List<Item> itemList; //批量修改后的商品集合
}
注意:接收List类型的数据必须是pojo的属性,如果方法的形参为ArrayList类型无法正确接收到数据?
除了ModelAndView以外,还可以使用Model(或者ModelMap --只需将model换成ModelMap 即可)来向页面传递数据,代码可以得到简化
@RequestMapping("/itemEdit")
public String queryItemById(HttpServletRequest request, Model model) {
// 从request中获取请求参数
String strId = request.getParameter("id");
Integer id = Integer.valueOf(strId);
// 根据id查询商品数据
Item item = this.itemService.queryItemById(id);
model.addAttribute("item", item);
return "itemEdit";
}
返回值问题
1.返回void(此时return无返回值)
@RequestMapping("queryItem")
public void queryItem(HttpServletRequest request, HttpServletResponse response) throws Exception {
// 1 使用request进行转发
// request.getRequestDispatcher("/WEB-INF/jsp/success.jsp").forward(request,
// response);
// 2 使用response进行重定向到编辑页面
// response.sendRedirect("/springmvc-web2/itemEdit.action");
// 3 使用response直接显示
response.getWriter().print("{\"abc\":123}");
}
扩展:转发和重定向的原理
使用转发时,jsp容器使用内部方法获取原来页面的请求,将这个请求转发到新的页面,新的页面继续处理这个请求,这个过程都是在服务器完成的,浏览器不知道. 相反,重定向方式的是第一个页面通知浏览器发送一个新的页面请求. 因此,转发用的是同一个request(参数可以共享)而重定向是两个不同的request(参数不共享)
2.返回字符串(即一个页面)
//指定逻辑视图名,经过视图解析器解析为jsp物理路径:/WEB-INF/jsp/itemList.jsp
return "itemList";
3.forward转发
Controller方法执行后继续执行另一个Controller方法
@RequestMapping("updateItem")
public String updateItemById(Item item) {
// 更新商品
this.itemService.updateItemById(item);
//结果转发到editItem.action,request可以带过去
return "forward: /itemEdit.action"; //执行另一个Controller方法
}
4.5.3.2. Redirect重定向
Contrller方法返回字符串可以重定向到一个url地址
@RequestMapping("updateItem")
public String updateItemById(Item item) {
// 更新商品
this.itemService.updateItemById(item);
// 重定向相当于执行了新的request和response,所以之前的请求参数都会丢失
// 如果要指定请求参数,需要在重定向的url后面添加 ?itemId=1 这样的请求参数
return "redirect:/itemEdit.action?itemId=" + item.getId(); //重定向到一个url地址
}
对比转发和重定向发现可以实现同样的功能,只是一个不需要重新携带参数,另一个需要