springMVC
SpringMVC分为:
-
前端控制器:当用户请求时综合调用映射器、适配器、控制器、视图解析器对用户的请求进行响应
-
映射器:对前端控制器发送的URL路径进行检查,如果路径错误返回404
-
适配器:寻找正确的控制器,如果找不到抛出异常
-
控制器:对用户的请求进行处理,将请求得到的数据以及要显示的视图放入ModelAndView对象中
-
视图解析器:接收ModelAndView对象,从中获取数据,经过处理组合成视图交给前端控制器进行处理
DispatcherServlet原理
1、根据请求的路径找到HandlerMethod(带有Method反射属性,也就是对应Controller中的方法)
2、然后匹配路径对应的拦截器
3、通过HandlerMapping接口实现类获得HandlerExecutionChain对象(包含HandlerMethod和拦截器)
4、有了HandlerExecutionChain之后,通过HandlerAdapter对象进行处理得到ModelAndView对象
调用HandlerMethod内部handle的时候:
1、使用各种HandlerMethodArgumentResolver接口实现类,完成参数绑定
2、使用到各种Converter接口实现类,完成类型转换
3、使用各种HandlerMethodReturnValueHandler接口实现类,处理返回值
4、最终返回值被处理成ModelAndView对象
5、这期间发生的异常会被HandlerExceptionResolver接口实现类进行处理
5、RequestToViewNameTranslator接口实现类将请求地址解析为视图名(若有手动设置视图名,则使用手动设置的)
6、通过各种View和ViewResolver接口实现类渲染视图(将Model中的数据放到request域对象中,页面的编译。。。)
前端控制器
前端控制器在web.xml中配置
<servlet>
<!-- 命名 -->
<servlet-name>springmvc</servlet-name>
<!-- 加载包中的前端控制器 -->
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- 让服务器已启动就开始加载文件springMVC.xml,用的是contextConfigLocation这个属性 -->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springMVC.xml</param-value>
</init-param>
<!-- 启动加载 -->
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<!-- 对应上面的命名 -->
<servlet-name>springmvc</servlet-name>
<!-- 对文件进行拦截来执行上面的程序, "/"代表拦截所有的-->
<url-pattern>/</url-pattern>
</servlet-mapping>
两种映射器
<!-- 映射器 -->
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"></bean>
<!-- 映射器2 -->
<bean class=" org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="mappings">
<props>
<!-- 这里的值要和控制器中的id相对应 -->
<prop key="/text1">text</prop>
<prop key="/text1">text</prop>
</props>
</property>
</bean>
两种适配器
<!-- 适配器 要实现Controller接口-->
<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"></bean>
<!-- 适配器2 要实现 HttpRequestHandler接口 -->
<bean class=" org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter"></bean>
控制器
<!-- 控制器 -->
<bean class="com.hemi.controller.MyController" name="/text" id="text"></bean>
后端控制器代码
public class MyController implements org.springframework.web.servlet.mvc.Controller{
@Override
public ModelAndView handleRequest(HttpServletRequest req, HttpServletResponse resp) throws Exception {
String username = req.getParameter("username");
String password = req.getParameter("password");
// req.setAttribute("username", username);
// req.setAttribute("password", password);
ModelAndView view = new ModelAndView();
if("lisi".equals(username)&&"123".equals(password)){
view.setViewName("Hello.jsp");
}
else{
view.setViewName("login.jsp");
}
return view;
}
}
视图解析器
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"></bean>
视图解析器的配置前缀后缀
<!-- 视图解析器 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!-- 前缀 -->
<property name="prefix" value="/"></property>
<!-- 后缀 -->
<property name="suffix" value=".jsp"></property>
</bean>
使用注解的方式配置springMVC
注意:注解适配器和映射器要一起使用才有效
注解适配器和映射器要一起使用才有效
<!-- 扫描包 -->
<context:component-scan base-package="com.hemi.controller"></context:component-scan>
<!-- 配置注解 1-->
<!-- 配置映射器注解 -->
<bean class=" org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping "></bean>
<!-- 配置适配器注解 -->
<bean class=" org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"></bean>
<!--配置注解2-->
<!-- 终极替换上面的注解 -->
<mvc:annotation-driven></mvc:annotation-driven>
- @RequestMapping("path"):在方法上使用该注解,配置对应的映射路径
@Controller
public class TextControler{
@RequestMapping("show1")
public ModelAndView show1(){}
}
springMVC后端控制器进行响应的三种方式
ModleAndView类型返回值:
-
view.setViewName("Hello"); 保存要显示的视图
-
view.addObject("password", password); 向域对象中保存数据(实际是保存到request域对象中)
@RequestMapping("show1")
public ModelAndView show1(HttpServletRequest req){
String username = req.getParameter("username");
String password = req.getParameter("password");
ModelAndView view = new ModelAndView();
view.addObject("username", username);
view.addObject("password", password);
view.setViewName("Hello");
return view;
}
@RequestMapping("show1")
public ModelAndView show1(HttpServletRequest req){
String username = req.getParameter("username");
String password = req.getParameter("password");
ModelAndView view = new ModelAndView();
view.addObject("username", username);
view.addObject("password", password);
view.setViewName("Hello");
return view;
}
- String类型返回值返回视图位置,使用Modle以及ModleMap来保存数据
@RequestMapping("show2")
public String show2(Model model,HttpServletRequest req){
String username = req.getParameter("username");
String password = req.getParameter("password");
model.addAttribute("username", username);
model.addAttribute("password", password);
return "Hello";
}
void类型返回值要用域对象来保存数据,通过请求转发和重定向来进行响应
@RequestMapping("show3")
public void show3(HttpServletRequest req,HttpServletResponse resp){
String username = req.getParameter("username");
String password = req.getParameter("password");
req.setAttribute("username", username);
req.setAttribute("password", password);
try {
req.getRequestDispatcher("Hello.jsp").forward(req, resp);
} catch (ServletException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
参数绑定
简单参数绑定:传入的数据是以key/value的形式进行传递,key和后端控制器的形参名字相同,可以使用注解@RequestParam("username")为后端控制器的形参名起别名,与key相对应
Pojo参数绑定:传入的数据是以key/value的形式进行传递,key值与Pojo中的属性名称相同
自定义类型: 进行date和数据类型的绑定,需要自己编写转换类
自定义转换类型配置步骤:
- 编写转换类
public class DateConvert implements Converter<String, Date>{
@Override
public Date convert(String source) {
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
try {
return format.parse(source);
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
}
- 在spring配置文件中进行配置
<mvc:annotation-driven conversion-service="conversionService">
</mvc:annotation-driven>
<bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
<property name="converters">
<list>
<bean class="com.hemi.controller.convert.DateConvert"></bean>
</list>
</property>
</bean>
- 在实体类中对绑定的Date属性值进行绑定
private String username;
private String password;
@DateTimeFormat(pattern="yyyy-MM-dd")
private Date date;
- 配置后端控制器
@RequestMapping("show4")
public String show4(Model model,User user){
model.addAttribute("user", user);
return "Hello";
}
参数绑定数组(数组和list集合一样)
前端页面
<form action="show5" method="post">
用户名:<input type="text" name="username"><br>
密码:<input type="password" name="password"> <br>
日期<input type="text" name="date"><br>
<!--传递list集合中装的是多个地址对象-->
<input type="text" placeholder="请输入地址" name="add[0].addres"><br>
<input type="text" placeholder="请输入编码" name="add[0].code"><br>
<input type="text" placeholder="请输入地址" name="add[1].addres"><br>
<input type="text" placeholder="请输入编码" name="add[1].code"><br>
<!--传递单个地址的实体对象-->
<input type="text" placeholder="请输入地址" name="add.addres"><br>
<input type="text" placeholder="请输入编码" name="add.code"><br>
<!--传递一个数组-->
<input type="checkbox" name="hobby" value="basketball">篮球<br>
<input type="checkbox" name="hobby" value="football">篮球<br>
<input type="checkbox" name="hobby" value="tennis">网球
<input type="submit" value="登录">
</form>
实体类
private String username;
private String password;
@DateTimeFormat(pattern="yyyy-MM-dd")
private Date date;
private List<Address> add;
控制器:
@RequestMapping("show5")
public String show5(String[] hobby){
}
全局异常处理
- 1、自定义异常类(继承Exception或RuntimeException)
public class CustomException extends Exception{
private String msg;
public CustomException(String msg) {
super(msg);
this.msg = msg;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
}
- 2、自定义异常处理器实现 HandlerExceptionResolver接口
public class ExceptionHandler implements HandlerExceptionResolver{
@Override
public ModelAndView resolveException(HttpServletRequest req, HttpServletResponse resp, Object object,
Exception ex) {
CustomException customException=null;
if (ex instanceof CustomException) {
customException=(CustomException)ex;
}else{
customException=new CustomException("未知错误");
}
ModelAndView view = new ModelAndView();
view.addObject("error", customException);
view.setViewName("error");
return view;
}
}
- 3、在springmvc配置文件中配置全局异常控制器
<!-- 定义全局异常 -->
<bean class="com.hemi.exception.handler.ExceptionHandler"></bean>
静态资源的释放
在配置文件中进行配置
<!-- 静态资源释放-->
<mvc:resources location="/image/" mapping="/image/*.*"></mvc:resources>
文件上传
1、编写配置文件
<!-- 配置文件上传处理 -->
<bean id="multipartResolver"
class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!-- 配置默认编码 -->
<property name="defaultEncoding" value="utf-8"></property>
<!-- 配置最大上传文件大小 -->
<property name="maxUploadSize" value="10485760000"></property>
<!-- 配置最大上传所用内存大小 -->
<property name="maxInMemorySize" value="40960"></property>
</bean>
2、上传单个文件,后端控制器:
public String upload(MultipartFile file,HttpServletRequest req) throws IllegalStateException, IOException{
if(file==null){
return "uploadFile";
}
//取出文件名
String filename = file.getOriginalFilename();
//根据文件的虚拟入境找到真实入境
String path = req.getServletContext().getRealPath("/temp");
File file2 = new File(path);
if (!file2.exists()) {
//创建目录
file2.mkdirs();
}
//将传入的文件按照真实入境和文件名写出来
file.transferTo(new File(file2,filename));
return "success";
}
3、批量上传文件,后端控制器
@RequestMapping("/upload1")
public String upload1(MultipartFile[] file,HttpServletRequest req) throws IllegalStateException, IOException{
for (MultipartFile multipartFile : file) {
if(file==null){
return "uploadFile";
}
String filename = multipartFile.getOriginalFilename();
String realPath = req.getServletContext().getRealPath("/team");
File file2 = new File(realPath);
if (!file2.exists()) {
file2.mkdirs();
}
multipartFile.transferTo(new File(file2,filename));
}
return "success";
}
4、编写前端表单页面
<form action="upload" method="post" enctype="multipart/form-data">
请上传文件:<input type="file" name="file">
<br>
<input type="submit" value="upload">
</form>
<hr>
<form action="upload1" method="post" enctype="multipart/form-data">
请上传文件:<input type="file" name="file">
<br>
请上传文件:<input type="file" name="file">
<br>
<input type="submit" value="upload1">
</form>
注意:
-
把form表单的默认的enctype 类型改成 enctype="multipart/form-data"
-
表单的提交方式设为:post
网友评论