学习笔记整理_springmvc

SpringMVC

HelloWorld

XML配置

  1. 创建webapp工程

  2. pom.xml中添加依赖spring-web, spring-webmvc

  3. 配置web.xml

    <!-- 配置中文乱码过滤器 -->
    <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>
    </filter>
    
    <filter-mapping>
        <filter-name>CharacterEncodingFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    
    <!-- 配置controller控制分发器 -->
    <servlet>
        <servlet-name>DispatcherServlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
          <param-name>contextConfigLocation</param-name>
          <param-value>classpath*:spring-mvc.xml</param-value>
        </init-param>
    </servlet>
    
    <servlet-mapping>
      <servlet-name>DispatcherServlet</servlet-name>
      <url-pattern>/</url-pattern>
    </servlet-mapping>
    
  4. 配置spring-mvc.config

    <!--扫包, 默认打开annotation-config-->
    <context:component-scan base-package="packageName" />
    
  5. 配置servlet

    //注册bean, 使得@RequestMapping被扫描到
    @Controller
    //@@RequestMapping("/user")
    public class UserServlet {
        //此注解可以写在类上, 后续访问路径则为 /user/save
        @RequestMapping("/save")//一般与方法名相同, 可随意
        public String save(){
            System.out.println("userServlet");
            return "index.jsp";
        }
    }
    
    
技术架构图

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EbhGo7hq-1598342120682)(F:\develop\Z_JavaEE\level_3_springMVC.assets\1595240212144.png)]

核心组件

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-M0ernMcQ-1598342120690)(F:\develop\Z_JavaEE\level_3_springMVC.assets\1595243801630.png)]

Controller层bean加载过滤
<context:component-scan base-package="com.cyy">
    <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
@ComponentScan(value = "com.cyy.controller", includeFilters = {
        @ComponentScan.Filter(type = FilterType.ANNOTATION, classes = {Controller.class})
})

静态资源放行

<!-- web.xml -->
	<servlet-mapping>
	  <servlet-name>DispatcherServlet</servlet-name>
	  <!-- 拦截所有资源,包括静态资源,所以需要配置静态资源的放行 -->
	  <url-pattern>/</url-pattern>
	</servlet-mapping>

<!-- springmvc配置文件-->
	<mvc:resources mapping="/css/**" location="/css/"/>
	<mvc:resources mapping="/js/**" location="/js/"/>
	               
	<!-- 使用默认,放行所有普通资源-->
	<mvc:default-servlet-handler/>

开启mvc相关注解

<mvc:annotation-driven />

注解驱动

配置类

@Configuration
@ComponentScan(
        value = "com.cyy",
        excludeFilters = {
                @ComponentScan.Filter(
                        type = FilterType.ANNOTATION,
                        classes = {Controller.class})
        })
public class SpringConfig {

}

基于servlet3.0规范, 自定义Servlet容器初始化配置类,加载springmvc核心配置类

public class MyServletInitConfig extends AbstractDispatcherServletInitializer {
    //配置
    @Override
    protected WebApplicationContext createServletApplicationContext() {
        AnnotationConfigWebApplicationContext aca = new AnnotationConfigWebApplicationContext();
        aca.register(SpringConfig.class);
        return aca;
    }
    
    //配置路径
    @Override
    protected String[] getServletMappings() {
        return new String[] {"/"};
    }
    
    @Override
    protected WebApplicationContext createRootApplicationContext() {
        return null;
    }
    
    //配置过滤器
    @Override
    public void onStartup(ServletContext servletContext) throws ServletException {
        super.onStartup(servletContext);
        
        CharacterEncodingFilter cf = new CharacterEncodingFilter();
        cf.setEncoding("UTF-8");
        
        FilterRegistration.Dynamic filter = servletContext.addFilter("characterEncoding", cf);
        filter.addMappingForUrlPatterns(EnumSet.of(DispatcherType.REQUEST, DispatcherType.INCLUDE, DispatcherType.FORWARD),
                false, "/*");
    }
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gqruZJOs-1598342120694)(F:\develop\Z_JavaEE\level_3_springMVC.assets\1595245865783.png)]

Request

请求参数

普通参数

//参数名与形参一致或者配置@RequestParam注解
//required默认为true, 没有参数则报错, name属性与value属性互为别名, 随意写
	@RequestMapping("/add")
    public String add(@RequestParam(value = "hobby", required = true, defaultValue = "jack") String[] sa) {
        for (String s : sa) {
            System.out.println(s);
        }
        //返回为要访问的资源,默认为forword
        return "/index.jsp";
    }

POJO类型(使用getter方法,与EL类似)

1. 基本类型与属性名相同
	?ame=jack
	
2. 引用类型使用 变量名.属性 传递数据
	?address.city=cq
	
3. 集合使用 list[index].属性 传递数据(list.get(index))
	?hobby=play&hobby=swim
	?list[0].hobby=play&list[1].hobby=swim
	
4. map使用 map['key'].属性 传递数据(map.get(key))
	?map['jack'].hobby=play&map['rose'].hobby=swim

数组(存储的是普通类型)

	//uri:   ?hobby=play&hobby=swim  请求参数数量需要大于1
	public String add(@RequestParam("hobby") String[] sa) {
        for (String s : sa) {
            System.out.println(s);
        }
        return "/index.jsp";
    }

集合(存储的是普通类型)

	//uri:   ?hobby=play&hobby=swim 请求参数数量需要大于1
	public String add(@RequestParam("hobby") List<String> sa) {
        for (String s : sa) {
            System.out.println(s);
        }
        return "/index.jsp";
    }

类型转换器

package org.springframework.core.convert.converter;

@FunctionalInterface
public interface Converter<S, T> {
	@Nullable
	T convert(S source);
}
ObjectToObjectConverter

xml配置

<mvc:annotation-driven conversion-service="conversionService"/>

<bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
    <property name="formatters">
        <set>
            <bean class="org.springframework.format.datetime.DateFormatter">
                <property name="pattern" value="yyyy-MM-dd"/>
            </bean>
        </set>
    </property>
</bean>

注解

//形参前, 或成员变量上
@RequestMapping("date")
public String dateFormat(@DateTimeFormat(pattern = "yyyy-MM-dd") Date date) {
    return "/index.jsp";
}
自定义类型转换器
//指定转换前后类型
public class MyDateConverter implements Converter<String, Date> {
    
    @Override
    public Date convert(String s) {
        DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
        Date date = null;
        try {
            date = dateFormat.parse(s);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return date;
    }
}

注册自定义类型转换器

<mvc:annotation-driven conversion-service="conversionService"/>

<bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
    <property name="converters">
        <set>
            <bean class="com.cyy.MyDateConverter"/>
        </set>
    </property>
</bean>

请求映射

注解

//方法上指定访问uri
//类上指定公共访问uri前缀
//请求返回的地址默认为当前路径,需要修改返回值
@RequestMapping
	//常用属性
	value="/user"
	method="RequestMethod.GET"
	params="name" //设定请求参数条件
	headers="content-type=text/*" //设定请求头消息条件
	consumes="text/*" //指定可以接收的请求正文类型(MIME类型)
	produces="text/*" //指定可以生成的响应正文类型(MIME类型)


Response

无数据页面跳转设定

当返回值为String时, 跳转至返回值指定页面

 @RequestMapping("/save")
    public String save(String name) {
        //默认为forword
        return "forword:index.jsp";
        //return "redirect:index.jsp";
    }
    

设定通用的访问路径简化配置(此时返回值字符串中不能使用forword和redirect)

<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/page/"/>
        <property name="suffix" value=".jsp"/>
</bean>

如果返回值为void, 默认使用方法名作为页面地址的前缀后缀

携带数据页面跳转
  1. 使用HttpServletRequest
	//使用HttpServletRequest
	@RequestMapping("date")
    public String request01(HttpServletRequest request) {
        request.setAttribute("key", "value");
        return "/index.jsp";
    }

  1. 使用Model类型形参进行数据传递
	@RequestMapping("date")
    public Model request01(Model model) {
        //addAttribute(String, Object);
        model.addAttribute("key", "value");
        return model;
    }

  1. 使用ModelAndView
	@RequestMapping("/save")
    public ModelAndView save(ModelAndView mv) {
        mv.addObject("key", "value");
        mv.setViewName("redirect:/index.jsp");
        return mv;
    }

返回数据, 无页面跳转
  1. 返回基本数据

    1. 使用HttpServletResponse
    2. @ResponseBody
  2. 返回JSON数据

    1. 使用第三方资源转化对象为json数据, 基于response返回

    2. 使用@ResponseBody, 集合也直接返回

      xml配置消息类型转换器: (使用@EnableWebMvc在配置类上, 替换xml)

FastJson

<mvc:annotation-driven>
    <mvc:message-converters register-defaults="true">
        <bean class="com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter">
            <property name="supportedMediaTypes" value="application/json"/>
            <property name="features">
                <list>
                    <value>WriteMapNullValue</value>
                    <value>WriteDateUseDateFormat</value>
                </list>
            </property>
        </bean>
    </mvc:message-converters>
</mvc:annotation-driven>

Jackson

添加依赖即为使用jackson作为序列化和反序列化的第三方组件

自定义ObjectMapper

public class CustomObjectMapper extends ObjectMapper {

    public CustomObjectMapper() {
        super();

        //去掉默认的时间戳格式
        configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
        //设置为东八区
        setTimeZone(TimeZone.getTimeZone("GMT+8"));
        //设置日期转换yyyy-MM-dd HH:mm:ss
        setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));

        // 设置输入:禁止把POJO中值为null的字段映射到json字符串中
        configure(SerializationFeature.WRITE_NULL_MAP_VALUES, false);
        //空值不序列化
        setSerializationInclusion(JsonInclude.Include.NON_NULL);
        // 反序列化时,属性不存在的兼容处理
        getDeserializationConfig().withoutFeatures(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
        // 序列化枚举是以toString()来输出,默认false,即默认以name()来输出
        configure(SerializationFeature.WRITE_ENUMS_USING_TO_STRING, true);
    }
}

配置自定义ObjectMapper
<mvc:annotation-driven>

    <mvc:message-converters>
        <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
            <!-- 自定义Jackson的objectMapper -->
            <property name="objectMapper" ref="customObjectMapper" />
            <property name="supportedMediaTypes">
                <list>
                    <value>text/plain;charset=UTF-8</value>
                    <value>application/json;charset=UTF-8</value>
                </list>
            </property>
        </bean>
    </mvc:message-converters>

</mvc:annotation-driven>

<bean name="customObjectMapper" class="com.cyy.CustomObjectMapper"/>

Servlet相关接口

  1. reques/response/session通过形参声明即可使用
  2. Head数据获取
    • 通过@RequestHeader(“headName”) 在处理器类中方法的形参处声明
  3. cookie数据获取
    • @CookieValue(“cookieName”)在处理器类中方法的形参处声明
  4. session数据获取
    • @SessionAttribute(“key”)在处理器类中方法的形参处声明
  5. session设置参数
    • @SessionAttributes(names={“name”,…}) 在处理器类上声明放入session的变量名, 适用于Model类型数据传参
模拟SpringBoot内嵌tomcat

实现 ServletContainerInitializer

配置文件META-INF下的javax.servlet.ServletContainerInitializer中配置全限定类名

异步请求响应

使用json前提导入jackson资源依赖

contentType:application/text
@RequestBody String message //普通数据传递

contentType:application/json
@RequestBody User user //对象数据传递

contentType:application/json
@RequestBody List<User> list //对象数据传递

@ReqeustBody//形参注解 前端必须指定contentType, 必须是POST提交,json数据格式必须为json字符串
@ResponseBody//方法注解, 返回值注解
	public @RequestBody List<User> getUsers(){}

跨域访问

ip端口协议域名有一个不同

//测试
//修改hosts,如 
//		127.0.0.1 www.cyy.com

//刷新dns		ipcongfig /displaydns
//    		 ipconfig /flushdns

@CrossOrigin//方法注解, 类注解 设置方法允许跨域访问

拦截器

类似于过滤器,但是属于springmvc,核心思想为AOP

  • filter属于servlet技术, Interceptor属于springmvc技术
  • filter对所有访问拦截, interceptor仅对springmvc的访问进行增强
自定义拦截器
public class MyInterceptor implements HandlerInterceptor {
    //前置拦截方法,执行此方法后执行业务方法
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        //handler是被调用的处理器对象, 本质上是反射中Method的一个包装类
        System.out.println("preHandle");
        return true;
        //返回false则拦截不进入原方法,不进入postHandle(),不进入afterCompletion()
    }
    
    //后置拦截方法,业务方法执行后再执行此方法
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception {
        //modelAndView对被拦截方法的返回值进行读取数据和页面信息,可以进行调整
        System.out.println("postHandle");
    }
    
    //完成后拦截方法
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception {
        System.out.println("afterCompletion");
    }
}

xml中配置
<mvc:interceptors>
   <mvc:interceptor>
       <!-- 先配置执行位置, 再配置执行类
		*表示任意名称, ** 表示当前路径及子路径
		-->
       <mvc:mapping path="/get*"/>
       <mvc:mapping path="/**"/>
       <mvc:mapping path="/save*"/>
       <!-- exclude-mapping 表排除 -->
       <mvc:exclude-mapping path="/get*" />
       <bean class="com.cyy.config.MyInterceptor"/>
   </mvc:interceptor>
</mvc:interceptors>

安全校验

token

session.setAttribute("token", token);

拦截器链

  • 多个拦截器配置顺序即为执行顺序

  • 所有后置在执行完才执行afterCompletion

  • 只要前置返回true, afterCompletion就会执行.

异常处理

@Component
public class MyExceptionResolver implements HandlerExceptionResolver {
    
    @Override
    public ModelAndView resolveException(HttpServletRequest httpServletRequest,
                                         HttpServletResponse httpServletResponse,
                                         Object o, Exception e) {
        ModelAndView modelAndView = new ModelAndView();
        if (e instanceof NullPointerException){
            modelAndView.setViewName("page.jsp");
        } else if (e instanceof ArithmeticException) {
            modelAndView.setViewName("index.jsp");
        } else {
            modelAndView.setViewName("index.html");
        }
        return modelAndView;
    }
}

@Component
@ControllerAdvice//类注解,设置当前类为异常处理类
public class AnnotationMyExceptionHandler {
    
    @ExceptionHandler(Exception.class)//方法注解, 指定异常的处理方式
    public GeneralResult exceptionHandler(Exception e) {
        GenaralResult result = new GenaralResult();
        if (e instanceof NullPointerException){
            ...
        } esle {
            ...
        }
        result.setCode(5001);
        result.setFlag(false);
        result.setMsg(e.getMessage());
        return result;
    }
    
}

注解处理器可以拦截到入参类型转换异常, 非注解无法拦截

项目异常处理方案
业务异常: 发送信息给用户,提醒规范操作
	规范的用户行为产生的异常
	不规范的用户行为操作产生的异常
	
	
系统异常: 发送固定信息给用户,安抚用户&发送消息给运维,提醒维护&记录日志
	项目运行过程中无法预计且无法避免的异常
其他异常: 发送固定信息给用户,安抚用户&发送消息给编程人员, 提醒维护(纳入预期范围)&记录日志
	编程人员未预期到的异常

通过自定义异常将所有的异常分类管理,已统一的格式对外呈现异常消息

实用技术

文件上传

springmvc提供MultipartResolver接口对通用操作进行封装
	CommonsMultipartResolver 调用了apache的上传下载组件

<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
        <property name="maxUploadSize" value="1024000000"/>
</bean>

	@RequestMapping("/fileupload")
    @ResponseBody
	//形参使用MultipartFile对象, fileName和前端表单中的name一致
    public String fileupload(MultipartFile file) throws IOException {
        file.getOriginalFilename();//获取上传文件名, 解析文件名及其扩展名
        imgfile.transferTo(new File("name.png"));
        return "index.html";
    }

服务器上传文件问题

  • 文件命名问题
  • 文件名过长问题(数据库保存文件名,本地另存文件名)
  • 文件保存路径
  • 重名问题

Restful

Representation State Transfer 一种网络资源的访问风格, 定义了网络资源的访问方式

优点: 隐藏资源的访问行为,通过地址栏无法得知具体操作/简化书写

行为约定: 并非规范, 可以打破
	get : 查询

	post : 保存
	 
	put : 更新
	
	delete : 删除

@RestController
@RequestMapping("/user")
public class UserServlet{
	@PutMapping("{id}")
    //@RequestMapping(value = "/user/{id}", method = RequestMethod.PUT)
    @ResponseBody
    public void test001(@PathVariable String id){
        //
    }
}   
//@GetMapping
//@DeleteMapping
//@PostMapping

web.xml配置开启表单restful风格的访问支持过滤器

<filter>
    <filter-name>hiddenHttpMenthodFilter</filter-name>
    <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>hiddenHttpMenthodFilter</filter-name>
    <servlet-name>DispatcherServlet</servlet-name>
</filter-mapping>

页面表单使用隐藏域提交请求类型,参数命名固定为"_method", 必须配合提交类型method=post使用

<form action="url" method="post">
	<input type="hidden" name="_method" value="put" />
    <inout type="submit" />
</form>

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值