文章目录

    • 三 SpringMvc
      • 3.1 说说SpringMvc三层架构?
      • 3.2 说说SpringMvc原理?
      • 3.3 说说SpringMvc的常用注解?
      • 3.4 谈谈转发与重定向?
      • 3.5 怎样解决乱码问题?
      • 3.6 过滤器与拦截器的区别?

三 SpringMvc

3.1 说说SpringMvc三层架构?

  • MVC是模型(Model)、视图(View)、控制器(Controller)的简写,是一种软件设计规范。
  • 是将业务逻辑、数据、显示分离的方法来组织代码。
  • MVC主要作用是降低了视图与业务逻辑间的双向偶合
  • MVC不是一种设计模式,MVC是一种架构模式。当然不同的MVC存在差异。

Model(模型):数据模型,提供要展示的数据,因此包含数据和行为,可以认为是领域模型或JavaBean组件(包含数据和行为),不过现在一般都分离开来:Value Object(数据Dao) 和 服务层(行为Service)。也就是模型提供了模型数据查询和模型数据的状态更新等功能,包括数据和业务。

View(视图):负责进行模型的展示,一般就是我们见到的用户界面,客户想看到的东西。

Controller(控制器):接收用户请求,委托给模型进行处理(状态改变),处理完毕后把返回的模型数据返回给视图,由视图负责展示。也就是说控制器做了个调度员的工作。

3.2 说说SpringMvc原理?

  • DispatcherServlet表示前置控制器,是整个SpringMVC的控制中心。用户发出请求,DispatcherServlet接收请求并拦截请求。
  • HandlerMapping为处理器映射。DispatcherServlet调用HandlerMapping,HandlerMapping根据请求url查找Handler
  • HandlerExecution表示具体的Handler,其主要作用是根据url查找控制器
  • HandlerExecution将解析后的信息传递给DispatcherServlet,如解析控制器映射等。
  • HandlerAdapter表示处理器适配器,其按照特定的规则去执行Handler。
  • Handler让具体的Controller执行。
  • Controller将具体的执行信息返回给HandlerAdapter,如ModelAndView。
  • HandlerAdapter将视图逻辑名或模型传递给DispatcherServlet
  • DispatcherServlet调用视图解析器(ViewResolver)来解析HandlerAdapter传递的逻辑视图名。
  • 视图解析器将解析的逻辑视图名传给DispatcherServlet
  • DispatcherServlet根据视图解析器解析的视图结果,调用具体的视图。
  • 最终视图呈现给用户。

我们来看一下吧:

3.3 说说SpringMvc的常用注解?

  • @RequestMapping:用于处理请求 url 映射的注解。
  • @RequestBody:注解实现接收http请求的json数据,将json转换为java对象。
  • @ResponseBody:注解实现将conreoller方法返回对象转化为json对象响应给客户。
  • @RestController:@ResponseBody+@Controller
  • @Controller: 用于标记在一个类上,使用它标记的类就是一个Spring MVC Controller 对象。
  • @PathVariable: 获取请求路径上的变量值。
  • @RequestParam:提交的域名称和处理方法的参数名不一致。

3.4 谈谈转发与重定向?

  • 直接转发方式(Forward),客户端和浏览器只发出一次请求,Servlet、HTML、JSP或其它信息资源,由第二个信息资源响应该请求,在请求对象request中,保存的对象对于每个信息资源是共享的。(服务端)

  • 间接转发方式(Redirect)实际是两次HTTP请求,服务器端在响应第一次请求的时候,让浏览器再向另外一个URL发出请求,从而达到转发的目的。(客服端)

  • 举个通俗的例子:

    直接转发就相当于:“A找B借钱,B说没有,B去找C借,借到借不到都会把消息传递给A”;

    间接转发就相当于:“A找B借钱,B说没有,让A去找C借”。

  • (1)转发:在返回值前面加"forward:"。

    (2)重定向:在返回值前面加"redirect:"。

3.5 怎样解决乱码问题?

  • 方法一
<!--过滤器问题-->
<filter>
<filter-name>encoding</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>encoding</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
  • 终极解决方法
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.Map;

/**
* 解决get和post请求 全部乱码的过滤器
*/
public class GenericEncodingFilter implements Filter {

@Override
public void destroy() {
}

@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
  //处理response的字符编码
  HttpServletResponse myResponse=(HttpServletResponse) response;
  myResponse.setContentType("text/html;charset=UTF-8");

  // 转型为与协议相关对象
  HttpServletRequest httpServletRequest = (HttpServletRequest) request;
  // 对request包装增强
  HttpServletRequest myrequest = new MyRequest(httpServletRequest);
  chain.doFilter(myrequest, response);
}

@Override
public void init(FilterConfig filterConfig) throws ServletException {
}

}

//自定义request对象,HttpServletRequest的包装类
class MyRequest extends HttpServletRequestWrapper {

private HttpServletRequest request;
//是否编码的标记
private boolean hasEncode;
//定义一个可以传入HttpServletRequest对象的构造函数,以便对其进行装饰
public MyRequest(HttpServletRequest request) {
  super(request);// super必须写
  this.request = request;
}

// 对需要增强方法 进行覆盖
@Override
public Map getParameterMap() {
  // 先获得请求方式
  String method = request.getMethod();
  if (method.equalsIgnoreCase("post")) {
      // post请求
      try {
          // 处理post乱码
          request.setCharacterEncoding("utf-8");
          return request.getParameterMap();
     } catch (UnsupportedEncodingException e) {
          e.printStackTrace();
     }
 } else if (method.equalsIgnoreCase("get")) {
      // get请求
      Map<String, String[]> parameterMap = request.getParameterMap();
      if (!hasEncode) { // 确保get手动编码逻辑只运行一次
          for (String parameterName : parameterMap.keySet()) {
              String[] values = parameterMap.get(parameterName);
              if (values != null) {
                  for (int i = 0; i < values.length; i++) {
                      try {
                          // 处理get乱码
                          values[i] = new String(values[i]
                                 .getBytes("ISO-8859-1"), "utf-8");
                     } catch (UnsupportedEncodingException e) {
                          e.printStackTrace();
                     }
                 }
             }
         }
          hasEncode = true;
     }
      return parameterMap;
 }
  return super.getParameterMap();
}

//取一个值
@Override
public String getParameter(String name) {
  Map<String, String[]> parameterMap = getParameterMap();
  String[] values = parameterMap.get(name);
  if (values == null) {
      return null;
 }
  return values[0]; // 取回参数的第一个值
}

//取所有值
@Override
public String[] getParameterValues(String name) {
  Map<String, String[]> parameterMap = getParameterMap();
  String[] values = parameterMap.get(name);
  return values;
}
}

3.6 过滤器与拦截器的区别?

过滤器与拦截器的区别:拦截器是AOP思想的具体应用。

过滤器

  • servlet规范中的一部分,任何java web工程都可以使用
  • url-pattern中配置了/*之后,可以对所有要访问的资源进行拦截

拦截器

  • 拦截器是SpringMVC框架自己的,只有使用了SpringMVC框架的工程才能使用
  • 拦截器只会拦截访问的控制器方法, 如果访问的是jsp/html/css/image/js是不会进行拦截的

更多推荐

2021最详细面试题(八)SpringMvc