SpringMVC

目录结构
在这里插入图片描述

配置web.xml

<servlet>
    <servlet-name>springDispatcherServlet</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <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>springDispatcherServlet</servlet-name>
/*会拦截.jsp  /不会
    <url-pattern>/</url-pattern>
  </servlet-mapping>

配置视图解析器

	<context:component-scan base-package="com"/>
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/page/"/>
        <property name="suffix" value=".jsp"/>
    </bean>

使用
直接返回字符串会自动拼接前后缀转发到目标页面

 @GetMapping("/hello")
    public String hello(){
        System.out.println("请求收到");
        return "success";
    }
  1. SpringMVC的前端控制器收到请求
  2. 来看请求地址和@RequestMapping标注的哪个注解,来找到使用哪个类的哪个方法
  3. 前端控制器找到了目标处理器类和目标方法,直接利用反射执行目标方法来处理
  4. 方法执行完成后会有一个返回值,SpringMVC认为这个返回值就是要去的页面地址
  5. 拿到返回值后拿到视图解析器进行拼串得到完整的页面地址
  6. 拿到页面地址,前端控制器帮我们转发到页面
如果不指定配置文件位置会默认去/WEB-INF/下找前端控制器名-servlet.xml配置文件		/WEB-INF/springDispatcherServlet-servlet.xml

DefaultServlet是tomcat来处理静态资源的,除过.jsp和serrvlet外剩下的都是静态资源,
	index.html:静态资源,tomcat就会在服务器下找到设个资源并返回,
	我们自己配置前端控制器的url-parent=/ 禁用了(重写)tomcat服务器中的DefaultServet

服务器的web.xml默认配置中有一个DefaultServlet是url-parent=/
我们配置中前端控制器url-pattern=/ 
静态资源就会来到DispatcherServlet(前端控制器)看那个方法的RequestMapping是处理这个静态资源
	包括所有的图片也都需要通过前端控制器去查找对应的处理方法
因为服务器中也默认配置了Jspservlet我们没有进行覆盖,所以可以访问.jsp页面

/* 直接拦截所有请求

在这里插入图片描述

@RequestMapping注解的参数
	value="/hello"
	params=	{}
		1.{"username"}  参数必须携带带username的参数  /hello?username="zhangsan"	{"username=123"} {"username!=123"}
		2.{"!username"} 发送请求时不能包含名为username的参数 带了会404
		3.{"username=123","!age"}  多规则  
		
	headers={}
		headers={"User-Agent=Google"}
		headers = "content-type=text/*"
		规定请求头 的任意字段
	consumes={} 只接受内容类型是那种的请求 
		规定请求头中的Content-Type
		consumes = "text/plain"
	  	consumes = {"text/plain", "application/*"}
	  	consumes = MediaType.TEXT_PLAIN_VALUE
	produces{}	告诉浏览器返回的内容是什么
		 produces = "text/plain"
		 produces = {"text/plain", "application/*"}
		 produces = MediaType.TEXT_PLAIN_VALUE
		 produces = "text/plain;charset=UTF-8"
		 produces = "application/json"
		给响应头加上Content-Type:text/html:charset=utf-8


ant风格的资源地址
	? :匹配文件名中的一个字符
	*  :匹配文件名中的任意字符
	** :匹配多层路径
	精确优先
	
	/user/*/createUser		/user/aaa/createUser  		/user/bbb/createUser		
	/use*/createUser	/user/createUser

	/user/**/createUser		/user/aaa/bbb/createUser 	/user/c/d/v/createUser		
	/user**/createUser
	
	/user/createUs?? 		/user/createUser 			/user/createUsaa			

@RequestParam()	获取请求参数
	value="user"
	required=false
	defaultValue="默认值"

@RequestHender():获取请求头中的值
	value="user"
	required=false
	defaultValue="默认值"
	
@CookieValue	获取某个cookie值
	value="JESSIONID"
	required=false
	defaultValue="默认值"


请求参数是POJO SpringMVC会自动根据请求参数进行封装
还可以级联属性赋值
	User{
		addreaa=new Address{
				ciry=""
			}
	}
	name=address.city	
	

参数 写原生API 只能支持一下原生参数
	Httpsession
	HttpServletRequest
	HttpServletResponse
		request.InputStream
		response.OutputStream
		request.Reader
		response.Writer
	Locale
	Principal 


乱码解决

配置过滤器


 
  <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>
    <init-param>
      <param-name>forceRequestEncoding</param-name>
      <param-value>true</param-value>
    </init-param>
    <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>


在这里插入图片描述

SpringMvc 除过在方法上传入原生的request和session外还能怎么样把数据带给页面
	可以在方法处传入Map ,Model ,ModelMap
		给这些参数里面保存的所有数据都会放在请求域中。可以在页面获取

这三个最终都是BindingAwareModelMap在工作 都会保存到请求域中
Map(interface:jdk)
Model(interface:)
ModelMap(继承自 LinkedHashMap)


BindingAwareModelMap()实现了Model接口并且继承了ModelMap	
方法的返回值可以变为ModelAndView类型

 @RequestMapping("handle")
 public ModelAndView handle(){
      ModelAndView modelAndView = new ModelAndView();
      modelAndView.setViewName("success");
      modelAndView.addObject("mag","hello");
      return modelAndView;
  }

既包含视图信息(页面地址)也包含模型信息(给页面携带的数据)而且数据也是放在request域中
SpringMvc提供了一种可以临时给Session域中保存数据的方式
给BindingAwareModelMap中保存数据,或者ModelAndView中的数据,同时给session中放一份
	value指定保存数据时要给session中放的数据的key
	@SessionAttributes(只能标注在类上)
	@SessionAttributes(
		value={"msg","haha"},	只要保存的是这种key的数据	给session中放入一份
		types={String.class}	只要是String类型都放入session中  ()		
	)

推荐用原生API
@ModelAttribute


参数
	方法位置:这个方法就会提前与目标方法运行
@ModelAttribute标在方法上的另外一个作用;
	可以把方法运行后的返回值按照方法上@ModelAttribute("abc")指定的key放到隐含模型中;
	如果没有指定这个key;就用返回值类型的首字母小写

@RequestMapping("/hello")
public String hello(@ModelAttribute("name")String name){
	
   System.out.println("请求收到"+name);
   return "success";
}

@ModelAttribute
   public void md(Map<String,Object> map){
   		map.put("name":"zhangsan")
       System.out.println("pre............");
   }

pre............
请求收到zhangsan

在这里插入图片描述

在这里插入图片描述

大致流程

doDispatch()
	根据当前请求地址找到哪个类能来处理
	mappedHandler = getHandler(processedRequest);
	
	noHandlerFound(processedRequest, response); 没有找到处理器就抛异常
	
	确定当前请求的处理程序适配器 能执行当前方法的适配器(反射工具)
	HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
	
	!mappedHandler.applyPreHandle(processedRequest, response) 处理之前
	
	实际调用处理程序。 适配器执行目标方法,将目标方法执行完成后的返回值作为视图名,设置保存到ModelAndView
	目标方法无论怎么写,最终适配器执行完成以后都会将执行后的信息封装成
	mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
	
	如果没有视图名	使用默认视图名 地址名
	applyDefaultViewName(processedRequest, mv);
	
	mappedHandler.applyPostHandle(processedRequest, response, mv);	后置处理器
	
	处理转发资源 根据方法最终执行完成后封装的ModelAndView转发到对应的页面 而且ModelAndView中的数据可以在请求域中获取
	processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
	

具体方法

根据当前请求地址找到哪个类能来处理 HandlerExecutionChain  封装了拦截器
DispatcherServlet
getHandler()
	HandlerExecutionChain getHandler(HttpServletRequest request)


		IOC启动创建controller时  就会扫描每个requestMapping能处理什么请求	,
		就保存在	HandlerMappings <Map> 中 
		如果请求过来直接看哪个handlerMapping中有这个请求的映射信息	
		for in this.handlerMappings	 比所有 看那个HandlerMapping能处理这个请求
			
			handlerMapping.getHandler(request)	
				Object handler = getHandlerInternal(request);	能处理的目标对象		HandlerMethod
					super.getHandlerInternal(request);
						HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);	/hello
				最终会调用executionChain .setHandler(handler)
				
				HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
				封装处理器....
			return executionChain 
确定当前请求的处理程序适配器 能执行当前方法的适配器(反射工具)
mappedHandler.getHandler()  目标处理器	com.controller.MyFirstController#hello()	HandlerMethod

如何找到目标处理器类的适配器。要拿适配器才去执行目标方法
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
		for (HandlerAdapter adapter : this.handlerAdapters)
			if (adapter.supports(handler) 
				supports(handler)
					AbstractHandlerMethodAdapter
						supports(handler instanceof HandlerMethod && supportsInternal((HandlerMethod) handler));
				
				return adapter
ModelAndView mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
	 handleInternal(request, response, (HandlerMethod) handler);
	 	ModelAndView handleInternal()
	 		mav = invokeHandlerMethod(request, response, handlerMethod);
	 		

  • SpringMvc九大组件
    • 全部都是接口 接口就是规范

	处理文件
/** MultipartResolver used by this servlet. */
	@Nullable
	private MultipartResolver multipartResolver;

处理国际化
	/** LocaleResolver used by this servlet. */
	@Nullable
	private LocaleResolver localeResolver;

处理主题
	/** ThemeResolver used by this servlet. */
	@Nullable
	private ThemeResolver themeResolver;

handler映射信息 
	/** List of HandlerMappings used by this servlet. */
	@Nullable
	private List<HandlerMapping> handlerMappings;

handler适配器
	/** List of HandlerAdapters used by this servlet. */
	@Nullable
	private List<HandlerAdapter> handlerAdapters;

springMvc的强大异常解析功能 异常解析器
	/** List of HandlerExceptionResolvers used by this servlet. */
	@Nullable
	private List<HandlerExceptionResolver> handlerExceptionResolvers;

没有返回地址就把请求地址当成返回地址
	/** RequestToViewNameTranslator used by this servlet. */
	@Nullable
	private RequestToViewNameTranslator viewNameTranslator;

springmvc中允许重定向携带数据功能
	/** FlashMapManager used by this servlet. */
	@Nullable
	private FlashMapManager flashMapManager;

视图解析器
	/** List of ViewResolvers used by this servlet. */
	@Nullable
	private List<ViewResolver> viewResolvers;

  • 组件初始化
    • 去容器中找这个组件,如果没有就用默认配置

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

protected void onRefresh(ApplicationContext context)
	initStrategies(context);
		initMultipartResolver(context);
		initLocaleResolver(context);
		initThemeResolver(context);
		initHandlerMappings(context);
			if (this.detectAllHandlerMappings) {
				// Find all HandlerMappings in the ApplicationContext, including ancestor contexts.
				Map<String, HandlerMapping> matchingBeans =
						BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
			else
				HandlerMapping hm = context.getBean(handleMapping, HandlerMapping.class);
			
			if (this.handlerMappings == null) {
				this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class);
					ClassPathResource resource = new ClassPathResource(DispatcherServlet.properties, DispatcherServlet.class);
					创建对象放入 this.handlerMappings
					List<T> strategies = new ArrayList<>(classNames.length);
					Class<?> clazz = ClassUtils.forName(className, DispatcherServlet.class.getClassLoader());
					Object strategy = createDefaultStrategy(context, clazz);
					strategies.add((T) strategy);
					return strategies 

		initHandlerAdapters(context);
		initHandlerExceptionResolvers(context);
		initRequestToViewNameTranslator(context);
		initViewResolvers(context);
		initFlashMapManager(context);
		
	

在这里插入图片描述


mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
	handleInternal(request, response, (HandlerMethod) handler);

		设置参数解析器
		invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
		
		设置返回值处理器
		invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
		
		容器
		ModelAndViewContainer mavContainer = new ModelAndViewContainer();
		
		执行标注@ModelAttribute的方法【提前运行】
		mav = invokeHandlerMethod(request, response, handlerMethod);
			modelFactory.initModel(webRequest, mavContainer, invocableMethod); 执行标注@ModelAttribute的方法【提前运行】
				invokeModelAttributeMethods(request, container); 	执行标注@ModelAttribute的方法
						Object returnValue = modelMethod.invokeForRequest(request, container);
							Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
								MethodParameter[] parameters = getMethodParameters();	获取方法参数
								args[i] = this.resolvers.resolveArgument(parameter, mavContainer, request, this.dataBinderFactory); 解析参数

			执行目标方法 调用方法并处理返回值
			invocableMethod.invokeAndHandle(webRequest, mavContainer);	【执行目标方法】
				invokeModelAttributeMethods(request, container);
					Object returnValue = modelMethod.invokeForRequest(request, container);
						Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
							MethodParameter[] parameters = getMethodParameters();
							args[i] = this.resolvers.resolveArgument(parameter, mavContainer, request, this.dataBinderFactory);
						doInvoke(args);
						method.invoke(getBean(), args);



先解析方法参数再执行目标方法


invocableMethod.invokeAndHandle(webRequest, mavContainer);	【执行目标方法】

调用方法并处理返回值
Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
	Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
		MethodParameter[] parameters = getMethodParameters(); 获取所有参数
		Object[] args = new Object[parameters.length];
		args[i] = this.resolvers.resolveArgument(parameter, mavContainer, request, this.dataBinderFactory);
			HandlerMethodArgumentResolver resolver = getArgumentResolver(parameter);	获取参数解析器
				
				先从缓存中获取
				HandlerMethodArgumentResolver result = this.argumentResolverCache.get(parameter); 
				
				如果没有遍历所有参数解析器 查看是否支持
				for (HandlerMethodArgumentResolver resolver : this.argumentResolvers)
				resolver.supportsParameter(parameter)
				
			resolver.resolveArgument(parameter, mavContainer, webRequest, binderFactory);


springmvc4.x的运行流程

在这里插入图片描述

视图解析

有前缀的转发和重定向操作,视图解析器就不会进行拼窜

  • forward 转发不会有视图解析器进行拼串

   @RequestMapping("/handle3")
    public String handle3(){

        return "forward:/handle2";
    }
    
    @RequestMapping("/handle2")
    public String handle2(){

       return "forward:/page/success.jsp";
    }
  • /是从当前项目下开始;SpringMVC会为路径自动的拼接上项目名

   @RequestMapping("/handle2")
    public String handle2(){

       return "redirect:/page/success.jsp";
    }

任何方法的返回值都会被包装成ModelAndView对象

processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
	render(mv, request, response);
		String viewName = mv.getViewName();
		view = resolveViewName(viewName, mv.getModelInternal(), locale, request);

			遍历所有视图解析器
			for (ViewResolver viewResolver : this.viewResolvers)
			View view = viewResolver.resolveViewName(viewName, locale);
				view = createView(viewName, locale);
					// Check for special "redirect:" prefix.
					if (viewName.startsWith(REDIRECT_URL_PREFIX)) {
					String redirectUrl = viewName.substring(REDIRECT_URL_PREFIX.length());
					RedirectView view = new RedirectView(redirectUrl,isRedirectContextRelative(), isRedirectHttp10Compatible());
					// Check for special "forward:" prefix.
					if (viewName.startsWith(FORWARD_URL_PREFIX)) 
					String forwardUrl = viewName.substring(FORWARD_URL_PREFIX.length());
					InternalResourceView view = new InternalResourceView(forwardUrl);
					return applyLifecycleMethods(FORWARD_URL_PREFIX, view);
					
		view.render(mv.getModelInternal(), request, response);	
			renderMergedOutputModel(mergedModel, getRequestToExpose(request), response);
				sendRedirect(request, response, targetUrl, this.http10Compatible);
					response.sendRedirect(encodedURL);
			
		

在这里插入图片描述

视图解析器只是为了得到视图对象;视图对象才能真正的转发(将模型数据全部放在请求域中)或者重定向到页面
视图对象才能真正的渲染视图;
流程图

自定义视图解析器

public class MyViewResolver implements ViewResolver, Ordered {

    private Integer order;
    /**
     * 根据视图名返回视图对象
     * @param viewName
     * @param locale
     * @return
     * @throws Exception
     */
    @Override
    public View resolveViewName(String viewName, Locale locale) throws Exception {
        if(viewName.startsWith("h:") ) {
            return new MyView();
        }
        return null;
    }

    @Override
    public int getOrder() {
        return this.order;
    }
    public void setOrder(Integer order){
        this.order=order;
    }
}


public class MyView implements View {
    @Override
    public String getContentType() {
        return "text/html";
    }

    @Override
    public void render(Map<String, ?> model, HttpServletRequest request, HttpServletResponse response) throws Exception {
        response.getWriter().write("<h1>ahhahhah</h1>");
    }
}
<bean class="com.config.MyViewResolver" id="myViewResolver">
	<property name="order" value="1"/>
</bean>

数据绑定

WebDataBinder
在这里插入图片描述

conversionService 类型转换器
	validators 		数据校验器
	bindingResult 	负责保存以及解析数据绑定期间数据校验产生的错误
	bindingErrorProcessor  绑定异常处理
	conversionService 	负责数据类型的转换以及格式化功能;
		不同类型的转换和格式化用它自己的converter
		conversionService 	中有非常多的Converter

在这里插入图片描述

在这里插入图片描述

resolver.resolveArgument(parameter, mavContainer, webRequest, binderFactory);
	WebDataBinder binder = binderFactory.createBinder(webRequest, attribute, name);
	bindRequestParameters(binder, webRequest);
		servletBinder.bind(servletRequest);
			addBindValues(mpvs, request);	
			doBind(mpvs);
				super.doBind(mpvs);
					applyPropertyValues(mpvs);
	
						绑定请求参数到目标对象
						getPropertyAccessor().setPropertyValues(mpvs, isIgnoreUnknownFields(), isIgnoreInvalidFields());
							for (PropertyValue pv : propertyValues) 
							setPropertyValue(pv);


在这里插入图片描述
在这里插入图片描述

GenericConversionService
private final Converters converters = new Converters();
	static class Converters
		add(GenericConverter converter)
	Object convert(@Nullable Object source, @Nullable TypeDescriptor sourceType, TypeDescriptor targetType)
	 	Object result = ConversionUtils.invokeConverter(converter, source, sourceType, targetType);
	 		return converter.convert(source, sourceType, targetType);

在这里插入图片描述

自定义类型转换器
conversionService:interface
它里面有 public interface Converter<S, T> 实际工作

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

  1. 实现Converter接口 写一个自定义的类型转换器
  2. Converter是ConverterService中的组件
    Converter需要放入ConverterService中
    将WebDataBinder中的ConversionServicer设置成我们这个加了自定义类型转换器的ConversionService
public class MyStringToEmployeeConverter implements Converter<String, User> {
    @Override
    public User convert(String source) {
        User user = new User();
        return user;
    }
}
<!--   使用自己设置的conversionService组件-->
    <mvc:annotation-driven conversion-service="conversionService"/>

<!--    告诉SpringMvc用我们自定义的类型转换器-->
    <bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
<!--    converters中添加自定义类型转换器   -->
        <property name="converters">
            <set>
                <bean class="com.config.MyStringToEmployeeConverter"/>
            </set>
        </property>
    </bean>

BeanDefinionParser bean定义信息解析器 解析xml成beanDefinion

在这里插入图片描述

在这里插入图片描述

  1. 动态资源能访问 web.xml中 url-parent= / 覆盖了 tom中的配置 便由SpringMvc来处理,mvc中的HandleMapping的handleMap中保存了每一个资源的映射信息,静态不能访问是因为handleMap中没有保存静态资源的映射请求信息,HandleAdapter来帮我们执行目标方法
  2. HandleMapping实现类发生变化所有请求过来直接交给tomcat进行处理(SimpleUrlHandlerMapping) /**=DefaultServletHandleMapping
  3. 都加 RequestMappingHandleMapping Simpxxxx 能处理的就处理,不能处理的就交给tomcat

在这里插入图片描述

数据格式化

在这里插入图片描述
在这里插入图片描述

ConversionserviceFactoryBearn 之前自定义的转换器不带格式化功能
FormattingConversionserviceFactoryBearn 带格式化功能的转换器 默认的也带
以后写自定义类型转化器时写FormattingConversionServiceFactoryBean

 <bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean"/>
@DateTimeFormat(pattern="yyyy-MM-dd")
private Date birth;

@NumberFormat(pattern="#,###,###.##")
private Double salary
数据校验

JSR303 规范
Hibernate Validator 第三方校验框架

在这里插入图片描述
在这里插入图片描述

导入校验框架包

<dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-validator</artifactId>
    <version>5.2.2.Final</version>
</dependency>
<dependency>
    <groupId>javax.validation</groupId>
    <artifactId>validation-api</artifactId>
    <version>1.1.0.Final</version>
</dependency>
<dependency>
    <groupId>org.jboss.logging</groupId>
    <artifactId>jboss-logging</artifactId>
    <version>3.2.1.Final</version>
</dependency>
<dependency>
    <groupId>com.fasterxml</groupId>
    <artifactId>classmate</artifactId>
    <version>1.1.0</version>
</dependency>
  <dependency>
      <groupId>org.hibernate.common</groupId>
      <artifactId>hibernate-commons-annotations</artifactId>
      <version>5.1.0.Final</version>
    </dependency>
@NotBlank 至少有一个字符

加入校验注解
@NotEmpty
private String name;

在SpringMVc封装对象的时候,告诉SpringMVC这个javaBean需要校验
public String addEmp(@Valid Employee employee)

校验结果
	给需要校验的javaBean后面紧跟一个BindingResult, BindingResult就是封装前一个bean的校验结果
public String addEmp(@Valid Employee employee,BindingResult result)

根据校验结果判断
	if(result.hasError){
		List<FieldError> errors=result.getFieldErrors()
		for(FieldError fielderror :errors){
			sout("消息"+rielderror.getDefaultMessage)
			sout("错误字段"+getField)
			
		}
		
	}

JSR303详见

忽略json数据返回 
	@JsonIgnore
	
json格式化
	@JsonFormat(pattern="yyyy-MM-dd")




HttpEntity 获取请求头数据 全部
@RequestHeader 只能获取某个请求头
public String test(HttpEntity<String> str){
} 


响应体中国内容的类型
public ResponseEntity<String> test(){
	
	HttpStatus statusCode
	MultiValueMap<String,String> headers=new HttpHeaders()
	String body

	HttpStatus.OK 
	headers.add("Set-Cookies","username=hhhhh")
	new ResponseEntity<String>(body,headers,statusCode)
	
}

文件下载

 @RequestMapping("/download")
    public ResponseEntity<byte[]> download(HttpServletRequest request) throws IOException {

        ServletContext servletContext = request.getServletContext();
        String realPath = servletContext.getRealPath("/static");

        FileInputStream fileInputStream = new FileInputStream(realPath);
        byte[] bytes = new byte[fileInputStream.available()];
        fileInputStream.read(bytes);
        fileInputStream.close();

        HttpHeaders httpHeaders = new HttpHeaders();
        httpHeaders.set("Content-Disposition","attachment:filename=aaa.txt");
        ResponseEntity<byte[]> responseEntity = new ResponseEntity<byte[]>(bytes, httpHeaders, HttpStatus.OK);

        return responseEntity;
    }

文件上传
表单准备: enctype= “multipart/form-data”

导包

<dependency>
      <groupId>commons-fileupload</groupId>
      <artifactId>commons-fileupload</artifactId>
      <version>1.4</version>
    </dependency>
     <dependency>
      <groupId>commons-io</groupId>
      <artifactId>commons-io</artifactId>
      <version>2.4</version>
    </dependency>

配置文件上传解析器

<!--    id必须是 multipartResolver-->
    <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
        <property name="maxUploadSize" value="#{1024*1024*20}"/>
        <property name="defaultEncoding" value="utf-8"/>
    </bean>
文件上传表单准备;enctype= "multipart/form-data"

@RequestMapping("/upload")
public String upload(@RequestParam("img")MultipartFile file) throws IOException {

   file.transferTo(new File("h:\\hah|"+file.getOriginalFilename()));

   return "";
}

多文件
在这里插入图片描述

乱码

拦截器

HandlerInterceptor:interface

在这里插入图片描述

preHandle 在目标方法运行之前 返回Boolean true放行 反之
postHandle 在目标方法运行之后调用
afterCompletion 在请求整个完成之后,来到目标页面之后 chain.doFilter()放行 资源响应之后

实现HandlerInterceptor


public class MyFirstInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {

    }
}

注册拦截器,配置拦截那些方法


    <mvc:interceptors>
<!--        默认拦截所有-->
<!--        <bean class="com.config.MyFirstInterceptor"/>-->

<!--        配置某个拦截器更详细的信息-->
        <mvc:interceptor>
<!--            只去拦截test01请求-->
            <mvc:mapping path="/test01"/>
            <bean class="com.config.MyFirstInterceptor"/>
        </mvc:interceptor>
    </mvc:interceptors>

拦截器的preHandle------目标方法-----拦截器postHandle-----页面-------拦截器的afterCompletion;
在这里插入图片描述

其他流程︰
1、只要preHandle不放行就没有以后的流程;
2、只要放行了 ,afterCompletion都会执行;

多拦截器
谁先配置谁优先

在这里插入图片描述

哪一块不放行以后都没有,已放行的拦截器的afterComplrtion还是会执行

在这里插入图片描述

doDispatch()
	拿到执行链,包含拦截器
	HandlerExecutionChain mappedHandler= getHandler(processedRequest);
	
	拿到所有执行拦截器,并执行preHandle方法		有记录最后一个放行拦截器的索引,从他开始把之前所有放行的拦截器的afterCompletion都执行
	if (!mappedHandler(HandlerExecutionChain ).applyPreHandle(processedRequest, response))return;
		 
	执行目标方法
	mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
	
	拿到所有执行拦截器,并逆序执行postHandle方法
	mappedHandler.applyPostHandle(processedRequest, response, mv);

	
	
	processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
		render(mv, request, response);
		页面渲染完成后
		mappedHandler.triggerAfterCompletion(request, response, null);

	只要有任何异常
	cache{triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
异常处理

在这里插入图片描述

AnnotationDrivenBeanDefinitionParser 开启注解驱动类

线从IOC容器中查找
HandlerExceptionResolver her =
						context.getBean("handlerExceptionResolver", HandlerExceptionResolver.class);


找不到就获取默认的
this.handlerExceptionResolvers = getDefaultStrategies(context, HandlerExceptionResolver.class);




org.springframework.web.servlet.HandlerExceptionResolver=
	org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver,	
	org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver,\
	org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver
try{
	try{
		//执行目标方法
		mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
	}catch (Exception ex) {
		执行后出现异常
		dispatchException = ex;
	}
	processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
		if (exception != null) {
			拿到目标方法
			Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);
			处理异常
			mv = processHandlerException(request, response, handler, ex);
				遍历所有异常解析器
				for (HandlerExceptionResolver resolver : this.handlerExceptionResolvers) 
				查看哪个解析器能够解析这个异常		3个异常解析器
				exMv = resolver.resolveException(request, response, handler, ex);
				如果都不能处理直接抛出去 给tomcat处理
				throw ex;
	
			
		}
	if (mv != null && !mv.wasCleared())
		render(mv, request, response);
}catch(){
	triggerAfterCompletion(processedRequest, response, mappedHandler, ex)
}

ExceptionHandlerExceptionResolver	处理 @ExceptionHandler
ResponseStatusExceptionResolver			@ResponseStatus
DefaultHandlerExceptionResolver			判断是否SpringMvc自带的异常

在这里插入图片描述

 /**
     * 告诉SpringMVC这个方法专门处理这个类发生的异常
     * 给方法上写一个Exception用来接收异常
     * 要携带异常信息不能给参数上写Model
     * 可以直接返回ModelAndView
     */
    @ExceptionHandler(value = {ArithmeticException.class,NullPointerException.class})
    public String handleException(){

        return "error";
    }

全局异常处理


/**
 * 集中处理所有异常
 *  要加入到IOC容器中  @ControllerAdvice 专门来处理异常的类
 */

@ControllerAdvice
public class MyProcessException {

    @ExceptionHandler(value = {ArithmeticException.class,NullPointerException.class})
    public String handleException(Exception e){

        return "error";
    }

//    精确优先
    @ExceptionHandler(value = {Exception.class})
    public String basicHandleException(Exception e){

        return "error";
    }
}



自定义异常 抛出 throw MyException()
@ResponseStatus(reason = "错误",value = HttpStatus.NOT_FOUND)
public class MyException extends RuntimeException {
}




SpringMVC运行流程:

1、所有请求,前端控制器(DispatcherServlet)收到请求,调用doDispatch进行处理
2、根据HandlerMapping中保存的请求映射信息找到,处理当前请求的,处理器执行链(包含拦截器)
3、根据当前处理器找到他的HandlerAdapter(适配器)
4、拦截器的preHandle先执行
5、适配器执行目标方法,并返回ModelAndView
          1)、ModelAttribute注解标注的方法提前运行
          2)、执行目标方法的时候(确定目标方法用的参数)
                    1)、有注解
                    2)、没注解:
                             1)、 看是否Model、Map以及其他的
                              2)、如果是自定义类型
                                             1)、从隐含模型中看有没有,如果有就从隐含模型中拿
                                              2)、如果没有,再看是否SessionAttributes标注的属性,如果是从Session中拿,如果拿不到会抛异常
                                             3)、都不是,就利用反射创建对象
6、拦截器的postHandle执行
7、处理结果;(页面渲染流程)
             1)、如果有异常使用异常解析器处理异常;处理完后还会返回ModelAndView
              2)、调用render进行页面渲染
                         1)、视图解析器根据视图名得到视图对象
                         2)、视图对象调用render方法;
               3)、执行拦截器的afterCompletion;

在这里插入图片描述

整合

SpringMVC和Spring整合的目的;分工明确;
SpringMVC的配置文件就来配置和网站转发逻辑以及网站功能有关的(视图解析器,文件上传解析器,支持ajax,xxx);
Spring的配置文件来配置和业务有关的(事务控制,数据源,xxx);

Spring管理业务逻辑组件

    <context:component-scan base-package="com.atguigu">
        <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
        <context:exclude-filter type="annotation" expression="org.springframework.web.bind.annotation.ControllerAdvice"/>
    </context:component-scan>

SpringMVC管理控制器组件;

<context:component-scan base-package="com.atguigu" use-default-filters="false">
        <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
        <context:include-filter type="annotation" expression="org.springframework.web.bind.annotation.ControllerAdvice"/>
    </context:component-scan>

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值