常用的MVC框架
JSF(过期,大部分企业已弃用)
JFinal(国产框架,易上手,使用不太广泛)
Struts1(比较早期,外企使用,特别日企)
Struts2(15年之前都比较流行,国内的老项目)
SpringMVC(目前最流行的MVC框架)
SpringMVC是目前最常用的MVC框架,现在大部分项目都是用的SpringMVC,但是也有一些老企业的老项目依然用的Struts2,Struts2是之前最流行的MVC框架,可是爆发了一次数据泄露事件后人们对这个框架也慢慢地失去了信任,有兴趣地可以自行百度一下这次数据泄露事件,所以目前掌握SpringMVC框架可以说是必要的。
这里说一下什么是MVC
什么是MVC模式
M model 模型层 dao层+entity层+pojo层,通常用于处理数据存取修改和移除,也保存处理应用程序中的数据逻辑。
V view 视图层 JSP 通常是用于展示对应的数据内容给用户浏览。
C control 控制层 Servlet 通常是用于模型层和视图层的交互的中间层。比如视图层将需要的数据发给控制层,由控制层访问模型层取到对应的数据,再由控制层将该数据发送给指定的视图层。
经典MVC javaBean+JSP+Serlvet
SpringMVC框架 spring框架的一个web拓展,提供了web层解决方案(基于MVC的设计架构)。
下面我们就开始对SpringMVC进行初体验。
1. 创建一个web工程
既然是Spring的web拓展,那当然得在web工程中进行试验,这里在创建工程时一定要记得勾选生成web.xml文件,不然还要自己写。
创建好web工程后,先在src目录下创建几个之后用到的包
2. 导入相关jar包
和以前javaBean+JSP+Serlvet时候的学习一样,将jar包放入lib文件夹下。
因为是Spring的web拓展,其实基本的包都差不多,只是主要工作图中框好的几个包上。
当然这些在官网下的lib里都是全的不用再去找。
3. 配置web.xml
为什么要对web.xml进行配置,因为我们现在不是和以前一样用servlet来进行控制了,我们现在是用controller进行控制,我们需要一个控制器,将所有的,以前的servlet请求都包装一下,处理这些请求防止被当做servlet处理。以下是对前端控制器的配置。
springmvc
org.springframework.web.servlet.DispatcherServlet
springmvc
*.action
其次我们还需要转换编码,回忆一下,最初我们是在servlet里用**request.setCharacterEncoding(“UTF-8”);**然后我们认识了过滤器,我们可以用过滤器实现所有的请求都进行编码装换,其实SpringMVC也是一个道理,代码如下。
encodingFilter
org.springframework.web.filter.CharacterEncodingFilter
encoding
utf-8
forceEncoding
true
encodingFilter
*.action
前端控制器配置和字符编码过滤器配置的class在jar包里可以找到,有兴趣也可以看看源码。
4. 配置springmvc-servlet.xml
接下来就是对servlet.xml文件的配置。而在这个配置文件里我们只需要配置视图解析器就好了。
springmvc-servlet.xml放置位子。
5. 创建控制台类
现在我们来写一个控制台类。
package cn.edu.fjut.controller;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
import cn.edu.fjut.pooj.TestFormPooj;
@Controller
public class TestController {
//控制器默认方法都是返回string类型字符串
@RequestMapping(value="/myhello")
public String helloworld(){
System.out.println("hello,springMVC");
return "index"; //返回字符串就是页面的名称 通过视图解析器解析成真正的页面 默认跳转方式是转发
}
}
记住前面的Spring所学,控制类的注解是@Controller。在控制类里,控制方法一般都是返回字符串类型。@RequestMapping(value="/myhello"),value的值就是这个控制方法的地址。
当没有其他参数的时候也可以写成这样。@RequestMapping("/myhello")。
跳转的如果是jsp页面,那么就只写jsp的名字,不要带后缀。如果跳转另一个控制方法下面再说。默认的是get转发方式。也可以在@RequestMapping注解里设置传递方式。
可以看见,除了我们常见的get和post还有很多的传递方式,我们后面再来学习其他的传递方式。
为什么说直接写jsp的名字不写后缀名,要知道在浏览器里不写后缀名会被当做servlet处理。这里就得说一下我们之前配置的视图解析器了,所有默认的转发都会经过视图解析器,视图解析器会按照配置给这个string加上前后缀。
现在我们打开服务器,看看能不能通过这个控制方法访问到index.jsp并且在控制台打印出hello,springMVC。
注意我们调用的控制方法不能像以前sevlet一样只写个名字就能直接调用了,要在后面加上.action的,也是我们在前端控制器里设置的 *.action。
不知道大家是否留意到,其实我们一直都没有对springmvc-servlet.xml在web.xml里配置,那么这个springmvc-servlet.xml是怎么被识别出来的呢,这要通过源码才能了解了。我忘记在源码的哪了有兴趣地可以自己查一下。了解了这个知识我们就可以将springmvc-servlet.xml换到src下存放了。
不过我这里还是给出修改springMVC配置文件读取位置和文件名的配置方法吧,参照着源码看。
在web.xml的前端控制器配置中,注入一个参数contextConfigLocation。
这个是比较重要的知识,理解记忆很重要。
1 用户发送请求到前端控制器(DispatcherServlet)
2 前端控制器(DispatcherServlet)接收到请求后,调用处理器映射器(HandlerMapping)
3 处理器映射器根据请求url找到具体的处理器(controller),生成处理器对象以及处理器拦截器,返回给前端控制器(DispatcherServlet)
4 前端控制器(DispatcherServlet)通过HandlerAdapter(处理器适配器)调用处理器(controller)
5 执行处理器(controller)
6 controller执行完成后返回ModelAndView
7 HandlerAdapter(处理器适配器)将处理器(controller)的执行结果ModelAndView返回给前端控制器(DispatcherServlet)
8 前端控制器(DispatcherServlet)将ModelAndView传递ViewReslover(视图解析器)
9 ViewReslover(视图解析器)将解析的结果返回具体View视图
10 前端控制器(DispatcherServlet) 对View进行渲染(将模型数据注入到视图层)
11 前端控制器(DispatcherServlet)响应用户请求
这个标签我们是第一次用到。
特点:
在控制器方法之前注释或者在控制器类声明上注释都可以,如果是注释在方法那边,表示要访问该方法的网络访问路径,如果是注释在类,表示为该类下面的所有方法都加了一个父级访问路径。
属性
Value:访问的路径名称;
Method :能够请求该控制器方法的请求方式.默认是get,除此以外还有post以及其他特殊请求方法.详见SpringMVC restful;
Header:请求的报文头,通常情况下不使用.;
Params:请求的参数。
1. View将数据发送给controller
@RequestMapping(value="/testformone")
public String testformone(HttpServletRequest request){
String username = "";
String[] hobby = null;
if(!request.getParameter("username").equals(null)){
username = request.getParameter("username");
}
if(!request.getParameter("hobby").equals(null)){
hobby = request.getParameterValues("hobby");
}
System.out.println("testformone");
System.out.println(username);
for (String string : hobby) {
System.out.println(string);
}
return "ShowOne";
}
@RequestMapping(value="/testformtwo")
public String testformtwo(String username,String[] hobby){
System.out.println("testformtwo");
System.out.println(username);
for (String string : hobby) {
System.out.println(string);
}
return "ShowTwo";
}
package cn.edu.fjut.pooj;
import java.util.Arrays;
public class TestFormPooj {
private String username;
private String[] hobby;
@RequestMapping(value="/testformthree")
public ModelAndView testformthree(TestFormPooj testFormPooj){
System.out.println("testformthree");
System.out.println(testFormPooj);
return "ShowThree";
}
可以明显看见代码量是越来越小了。
2. controller将数据保存到请求域发送给view
我们在刚才接收的数据上,把数据返回给jsp来作为示例。
@RequestMapping(value="/testformone")
public String testformone(HttpServletRequest request){
String username = "";
String[] hobby = null;
if(!request.getParameter("username").equals(null)){
username = request.getParameter("username");
}
if(!request.getParameter("hobby").equals(null)){
hobby = request.getParameterValues("hobby");
}
System.out.println("testformone");
System.out.println(username);
for (String string : hobby) {
System.out.println(string);
}
request.setAttribute("username", username);
return "ShowOne";
@RequestMapping(value="/testformone")
public String testformone(HttpServletRequest request,Model model){
String username = "";
String[] hobby = null;
if(!request.getParameter("username").equals(null)){
username = request.getParameter("username");
}
if(!request.getParameter("hobby").equals(null)){
hobby = request.getParameterValues("hobby");
}
System.out.println("testformone");
System.out.println(username);
for (String string : hobby) {
System.out.println(string);
}
model.addAttribute("username", username);
return "ShowOne";
}
@RequestMapping(value="/testformtwo")
public String testformtwo(String username,String[] hobby,Mapmap){
System.out.println("testformtwo");
System.out.println(username);
for (String string : hobby) {
System.out.println(string);
}
map.put("username", username);
return "ShowTwo";
//return "redirect:/ShowTwo.jsp";
}
@RequestMapping(value="/testformthree")
public ModelAndView testformthree(TestFormPooj testFormPooj){
System.out.println("testformthree");
System.out.println(testFormPooj);
ModelAndView modelAndView = new ModelAndView();
modelAndView.setViewName("ShowThree");
modelAndView.addObject("username",testFormPooj.getUsername());
return modelAndView;
}
其实从代码量上来说,老办法还简短一点,但是我依旧推荐后面的几种方法,因为利用servlet API实在太大众了。。。
默认直接经过视图解析的跳转方式都是转发方式,如果需要直接重定向跳转到另一个页面,那么要在return 的字符串之前加入关键字”redirect:”
注意:重定向是不经过视图解析器的。
特殊的跳转(控制方法跳转控制方法)
controller之间的跳转,都不能经过视图解析器.通常采用以下两种方式:
1.控制器A重定向跳转控制器B
2.控制器A 将数据转发到 控制器B
老问题新回答,ajax局部刷新技术的重要性不想再重复了,可是在SpringMVC中怎么使用ajax技术,其难点在哪。
根据以前的思路,其实并没有什么难点,但是以前在servlet中并没有进行任何的转发或者重定向操作,但是SpringMVC中控制方法的都是以string作为返回值类型的,怎么解决这个问题。
1. 利用servlet API方式实现 ajax的效果
其实很简单,老方法照样用,而且SpringMVC的控制方法返回类型并不是不能更改的。
2. 利用@responseBody实现ajax
其实我们想一下,json最终也是一个字符串,我们能不能将json直接给返回回去。
不过这接这样写会出现乱码问题,以前我们都是通过response.setContentType(“text/html;charset=utf-8”);规定编码,但是现在怎么办。现在我们通过对springmvc-servlet.xml配置来规定编码。
这个配置有点长,但是和第三个方法冲突的不能同时出现所以我是写完后截图的没有留下代码。
配置的时候要小心以免配置错误。
3. 直接返回要转换成json的对象,由springMVC过滤器自己进行转换(建议使用这种配置)
text/html;charset=UTF-8
记得获取json的时候导入gson.jar
还是不建议用老方法实现ajax,首先代码量上就输了,虽然后面两种配置很长很容易配错,但是一旦配好了后面使用就很方便了。