46.javaEE-框架(三)-springMVC

本文章的架构如下图:
在这里插入图片描述

1.springMVC概述

MVC设计模式是一种通用的软件编程思想
在MVC设计模式中认为, 任何软件都可以分为三部分组成:

(1)控制程序流转的控制器(Controller)
(2)封装数据处理数据的模型(Model)
(3)负责展示数据的视图(view)

并且在MVC设计思想中要求一个符合MVC设计思想的软件应该保证上面这三部分相互独立,互不干扰,每一个部分只负责自己擅长的部分。
如果某一个模块发生变化,应该尽量做到不影响其他两个模块。这样做的好处是,软件的结构会变得更加的清晰,可读性强。有利于后期的扩展和维护,并且代码可以实现复用。
在这里插入图片描述

2.springMVC的产生及其作用

2.1 servlet的缺点

1、通常情况下,一个Servlet类只负责处理一个请求,若项目中有成百上千个请求需要处理,就需要有成百上千个Servlet类,这样会使得项目中Servlet类的个数暴增;
2、在Servlet3.0版本之前,每一个Servlet都需要在web.xml文件中至少做八行配置信息,配置内容多且繁琐。当Servlet特别多时,web.xml配置量太多,不利于团队开发;
3、当通过客户端提交参数到服务器,通过Servlet进行接收时,无论数据本身是什么格式,在Servlet中一律按照字符串进行接收,后期需要进行类型转换,复杂类型还需要特殊处理,特别麻烦!
4、servlet具有容器依赖性,必须放在服务器中运行,不利于单元测试;

2.2 springMVC的执行原理

Springmvc是spring框架的一个模块,spring和springmvc无需中间整合层整合Springmvc是一个基于mvc的web框架.
具体原理图如下:
在这里插入图片描述

(1) 用户发送请求 至 前端控制器(DispatcherServlet);
提示:DispatcherServlet的作用:接收请求,调用其它组件处理请求,响应结果,相当于转发器、中央处理器,是整个流程控制的中心
(2) 前端控制器(DispatcherServlet)收到请求后调用处理器映射器(HandlerMapping)处理器映射器(HandlerMapping)找到具体的Controller(可以根据xml配置、注解进行查找),并将Controller返回给DispatcherServlet;
(3) 前端控制器(DispatcherServlet)调用处理器适配器(HandlerAdapter)。处理器适配器经过适配调用具体的Controller;(Controller–>service --> Dao --> 数据库) Controller执行完成后返回ModelAndView,
提示:Model(模型数据,即Controller处理的结果,Map) View(逻辑视图名,即负责展示结果的JSP页面的名字)
处理器适配器(HandlerAdapter)将controller执行的结果(ModelAndView)返回给前端控制器(DispatcherServlet);
(4).前端控制器(DispatcherServlet)将执行的结果(ModelAndView)传给视图解析器(ViewReslover)
视图解析器(ViewReslover)根据View(逻辑视图名)解析后返回具体JSP页面
(5).前端控制器(DispatcherServlet)根据Model对View进行渲染(即将模型数据填充至视图中);
前端控制器(DispatcherServlet)将填充了数据的网页响应给用户。

其中整个过程中需要开发人员编写的部分有 Controller、Service、Dao、View;

3.springmvc快速入门

3.1 导入依赖
<!-- SpringMVC -->
	<dependency>
		<groupId>org.springframework</groupId>
		<artifactId>spring-webmvc</artifactId>
		<version>${spring.version}</version>
	</dependency>
3.2 编写配置文件(web.xml),注入dispacherServlet对象.

因为jave 的web项目的入口是web.xml,并且servlet注册也是在web.xml中,所以我们需要在web.xml中注册SpringMVC的dispactherServlet对象.

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns="http://java.sun.com/xml/ns/javaee"
	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
	id="WebApp_ID" version="2.5">
	
	<!-- 配置springmvc前端控制器, 将所有请求交给springmvc来处理 -->
	<servlet>
		<servlet-name>springmvc</servlet-name>
		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
		
		<!-- 配置springmvc核心配置文件的位置,默认Springmvc的配置文件是在WEB-INF目录下,默认的名字为springmvc-servlet.xml,如果要放在其他目录,则需要指定如下配置:
		-->
		<init-param>
			<param-name>contextConfigLocation</param-name>
			<param-value>classpath:springmvc-config.xml</param-value>
		</init-param>		
	</servlet>
	<!-- 其中的斜杠(/)表示拦截所有请求(除JSP以外), 所有请求都要经过springmvc前端控制器 -->
	<servlet-mapping>
		<servlet-name>springmvc</servlet-name>
		<url-pattern>/</url-pattern>
	</servlet-mapping>

</web-app>
3.3 配置springMVC的配置文件
<?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:mvc="http://www.springframework.org/schema/mvc"
	xmlns:context="http://www.springframework.org/schema/context"
	xsi:schemaLocation="http://www.springframework.org/schema/mvc
						http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
						http://www.springframework.org/schema/beans
						http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
						http://www.springframework.org/schema/context
          				http://www.springframework.org/schema/context/spring-context-4.0.xsd">
	
	<!-- 1.配置前端控制器放行静态资源(html/css/js等,否则静态资源将无法访问) -->
	<mvc:default-servlet-handler/>
	
	<!-- 2.配置注解驱动,用于识别注解(比如@Controller-->
	<mvc:annotation-driven></mvc:annotation-driven>
	
	<!-- 3.配置需要扫描的包:spring自动去扫描 base-package 下的类,
		如果扫描到的类上有 @Controller@Service@Component等注解,
		将会自动将类注册为bean 
	 -->
	<context:component-scan base-package="com.tedu.controller">
	</context:component-scan>
	
	<!-- 4.配置内部资源视图解析器
		prefix:配置路径前缀
		suffix:配置文件后缀
	 -->
	<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
		<property name="prefix" value="/WEB-INF/pages/"/>
		<property name="suffix" value=".jsp"/>
	</bean>
	
	
</beans>
3.4创建并实现HelloController类
@Controller /* 这个注解表示当前类是属于控制层 */
public class HelloController {
	/* http://localhost/项目名称/hello */
	@RequestMapping("/hello/{age}") 
	/* 这个注解用于:映射请求的资源路径(/hello)和当前方法(hello)的对应关系
	 * 当浏览器请求 /hello 路径时, 将会访问(执行)当前这个方法 */
	public String hello(@Param String name,@Pathvariable Integer age) {
		System.out.println("hello springmvc...");
		return "home";
	}
}

4.SpringMVC编写Controller层的注意事项

4.1 请求方式
(1)get请求
@GetMapping(“url”)
或者
@RequestMapping(method = RequestMethod.GET,value = “url”)
(2)post请求
@PostMapping(“url”)
或者
@RequestMapping(method = RequestMethod.POST,value = “url”)
(3) delete请求
@DeleteMapping(“url”)
或者
@RequestMapping(method = RequestMethod.DELETE,value = “url”)
(4) 修改请求
@PutMapping(“url”)
或者
@RequestMapping(method = RequestMethod.PUT,value = “url”)

代码如下:

 @GetMapping
	 @PostMapping
	 @DeleteMapping
	 @PutMapping
	 @RequestMapping(method = RequestMethod.POST,value = "{module}/{moduleUI}")
	 public String doModuleUI(
			 @PathVariable String moduleUI) {
		 return "sys/"+moduleUI;
	 }

4.2参数映射
(1)解析前台传过来的参数
@RequestParam和@RequestBody
@RequestParam(“参数名”)

用来处理Content-Type: 为
application/x-www-form-urlencoded编码的内容。(Http协议中,如果不指定Content-Type,则默认传递的参数就是application/x-www-form-urlencoded类型)

	@GetMapping("doFindObjectById")
	public JsonResult doFindObjectById(@RequestParam("id") Integer id) {
		return new JsonResult(sysUserService.findObjectById(id));
	}

@RequestBody(“参数名”)

处理HttpEntity传递过来的数据,一般用来处理非Content-Type:
application/x-www-form-urlencoded编码格式的数据。

GET请求中,因为没有HttpEntity,所以@RequestBody并不适用。
POST请求中,通过HttpEntity传递的参数,必须要在请求头中声明数据的类型Content-Type,SpringMVC通过使用HandlerAdapter
配置的HttpMessageConverters来解析HttpEntity中的数据,然后绑定到相应的bean上。

	@PostMapping("doUpdateObjectById")
	public JsonResult doFindObjectById(@RequestBody("id") Integer id) {
		return new JsonResult(sysUserService.findObjectById(id));
	}

总结
在GET请求中,不能使用@RequestBody。
在POST请求,可以使用@RequestBody和@RequestParam,但是如果使用@RequestBody,对于参数转化的配置必须统一。

注意:
@RequestBody和@RequestParam注解修饰的属性,如果没有传递是会报错的,因为如果没设置,默认是必须传递.
设置可以不传递

	//@RequestParam表示参数名为id,可以不传递本参数
	@GetMapping("doFindObjectById")
	public JsonResult doFindObjectById(@RequestParam(value = "id",required = false) Integer id) {
		return new JsonResult(sysUserService.findObjectById(id));
	}

(2)url中的参数
注解:@PathVariable 修饰
从url路劲中获取参数

 @RequestMapping("{module}/{moduleUI}")
	 public String doModuleUI(
			 @PathVariable String moduleUI) {
		 return "sys/"+moduleUI;
	 }

4.3 请求转发与重定向
(1) 请求转发

/* 测试请求转发(forward) */
@RequestMapping("testForward")
public String testForward(){
	System.out.println("测试请求转发(forward)...");
	return "forward:hello";//转发到路劲 hello下
}

(2) 重定向

/* 测试请求重定向(redirect) */
@RequestMapping("testRedirect")
public String testRedirect(){
	System.out.println("测试请求重定向(redirect)...");
	return "redirect:hello"; //重定向到 hello路劲下
}

4.4 响应
分类

1.响应页面
1.1 控制层的类上只标注@Controller类,没有标@ResponseBody;
1.2 方法是也没有@ResponseBody注解

@Controller
public class DoorController {

2.响应json数据
方式1:类上标注@ResponseBody注解.

@Controller
@ResponseBody
public class DoorController {

方式2:类上标注@RestController;
这个注解等于@Controller + @ResponseBody ;并且表示本类的所有方法都响应的是json数据

//等于 @Controller + @ResponseBody
@RestController
public class DoorController {

方式3:方法上标注注解@ResponseBody

@Controller
public class DoorController {
	@Autowired
	private DoorMapper doorMapper;
	
	//方法上并没有标注@ResponseBody注解,且类上也没有表示本方法响应页面
	@RequestMapping("/doorList") //响应页面返回值为String
	public String toDoorlist(Model model) {
		List<Door> doorList = doorMapper.findAll();
		model.addAttribute("doorList", doorList);
		//他会到我们在spring-mvc.xml中拿取,前缀和后缀,拼接起来,去找相应的页面
		return "door_list"; 
	}

4.5 乱码处理
springmvc也提供了解决请求参数乱码的方案,就是在web.xml中加入如下代码,可以解决POST提交参数乱码:
添加拦截器:

<!-- 乱码处理过滤器 -->
	<filter>
		<filter-name>encodingFilter</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>
	</filter>
	<filter-mapping>
		<filter-name>encodingFilter</filter-name>
		<!-- 指定拦截方式为拦截所有请求 -->
		<url-pattern>/*</url-pattern>
	</filter-mapping>

4.6 异常处理
这是SpringMVC的异常处理,也就是Controller层的异常处理,如果出现异常怎么处理.
(1)局部异常
局部异常是指的定义在Controller类中的异常处理方式,只能指定本类的异常处理方式.
例如代码:

 		//局部异常处理
	 @ExceptionHandler(RuntimeException.class)
	 @ResponseBody
	 public JsonResult doHandleRuntimeException(RuntimeException e) {
		 JsonResult jsonResult = new JsonResult(e);
		 return jsonResult;
	 }

说明:
使用注解 @ExceptionHandler(RuntimeException.class)表示捕获RuntimeException类型的异常,如果本类执行过程中发生了这个类型的异常,则走本代码.

(2) 全局异常
全局异常控制所有的Controller收到或者发生的异常,这里有个规则,如果该类有局部异常,则走局部异常,没有局部异常则走全局异常.
具体代码:

/**
 * @ControllerAdvice 描述的类表示一个全局异常处理类
 * @ExceptionHandler 描述的方法为一个异常处理方法
 * 全球异常处理类
 */
//@ControllerAdvice  //这个是标注此类为处理controller层的全局异常类
//@ResponseBody
@RestControllerAdvice//==@ControllerAdvice+@ResponseBody
public class GlobalExceptionHandler {
	
	  @ExceptionHandler(RuntimeException.class)
	  //@ResponseBody
	  public JsonResult doHandleRuntimeException(
			  RuntimeException e) {
		  e.printStackTrace();
		  return new JsonResult(e);
	  }
	    @ExceptionHandler(ShiroException.class)
		@ResponseBody
		public JsonResult doHandleShiroException(
				ShiroException e) {
			JsonResult r=new JsonResult();
			r.setState(0);
			if(e instanceof UnknownAccountException) {
				r.setMessage("账户不存在");
			}else if(e instanceof LockedAccountException) {
				r.setMessage("账户已被禁用");
			}else if(e instanceof IncorrectCredentialsException) {
				r.setMessage("密码不正确");
			}else if(e instanceof AuthorizationException) {
				r.setMessage("没有此操作权限");
			}else {
				r.setMessage("系统维护中");
			}
			e.printStackTrace();
			return r;
		}
}
5.restful风格

5.1 前端发起请求
前端发起增删改查的请求,并且使用不同传输方式,则有两种方式可以实现不同的增删改查的请求方式.

(1) 是ajax请求类型get/post/put/delete

$.ajax({
    url: "${pageContext.request.contextPath}/emp/" + id,
    type: "PUT",//请求方式
    data: $("#app form").serialize(),
    success: function (result) {
        alert("操作成功!");
    }
});

(2) 通过form表单将post请求转化成相应的请求方式

form action="http://localhost:8099/post" method="post">
    <input type="text" name="username">
    <br>
    <input type="text" name="age">
    <br>
    <input type="submit" value="post提交">
</form>
    <hr>
<form action="http://localhost:8099/put" method="post">
    <input name="username" type="text">
    <br>
    <input type="text" name="age">
    <br>
    <input type="hidden" name="_method" value="put">
    <input type="submit" value="put提交">
</form>
    <hr>
<form action="http://localhost:8099/delete" method="post">
    <input name="id" type="text">
    <br>
    <input type="hidden" name="_method" value="delete">
    <input type="submit" value="delete提交">
</form>

注意:
1.form表单发起请求;
2.表单的属性method = “post”;
3.form表单中一定要有一个input标签,可以用delete/put/post等

5.2 后端的controller
如果后端请求想要接受到前端的rest风格的请求,根据前台发起请求的方式有两个步骤:

  1. 如果前台是ajax的形式发起请求,此步骤可省略.以表单的形式发起请求,则:

(1) 如果后台是普通的web项目则需要在web.xml中配置拦截器

<filter>  
  <filter-name>HiddenHttpMethodFilter</filter-name>  
  <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>  
</filter>  
<filter-mapping>  
  <filter-name>HiddenHttpMethodFilter</filter-name>  
  <url-pattern>/*</url-pattern>  
</filter-mapping> 

(2) 如果是spring boot项目,则springboot默认配置了一个类HiddenHttpMethodFilter .
该类的码如下:

public class HiddenHttpMethodFilter extends OncePerRequestFilter {
    private static final List<String> ALLOWED_METHODS;
    public static final String DEFAULT_METHOD_PARAM = "_method";
    private String methodParam = "_method";

2.配置具体的Controller映射
(1)get请求
@GetMapping(“url”)
或者
@RequestMapping(method = RequestMethod.GET,value = “url”)
(2)post请求
@PostMapping(“url”)
或者
@RequestMapping(method = RequestMethod.POST,value = “url”)
(3) delete请求
@DeleteMapping(“url”)
或者
@RequestMapping(method = RequestMethod.DELETE,value = “url”)
(4) 修改请求
@PutMapping(“url”)
或者
@RequestMapping(method = RequestMethod.PUT,value = “url”)

代码如下:

@GetMapping("/get")
public String getMethod(Integer id){
    return "get方法成功!!"+ id;
}

@PostMapping("/post")
public String postMethod(String username,Integer age){
    return "post方法成功!!"+ username + age;
}

@PutMapping("/put")
public String putMethod(String username,Integer age){
    return "put方法成功!!"+ username + age;
}

@DeleteMapping("/delete")
public String deleteMethod(Integer id){
    return "delete方法成功!!"+ id;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值