Spring MVC入门笔记

Spring MVC基础知识

1. 创建web应用

新建Maven项目
点击File -> Project Structure -> Facets -> +号 -> Web
Spring MVC入门笔记_第1张图片
修改文件描述符路径为硬盘:\项目名\src\main\存储页面的文件夹(如:webapp)\WEB-INF\web.xml
修改Web页面路径为硬盘:\项目名\src\main\存储页面的文件夹(如:webapp)
创建Artifact
Spring MVC入门笔记_第2张图片
点击右上角Current File -> Edit Configurations
Spring MVC入门笔记_第3张图片
点击 +号,找到 Tomcat Server -> local
点击 Application Server 后面的 Configure,将Tomcat Home设为保存Tomcat的路径。
Spring MVC入门笔记_第4张图片
点击Deployment, 选择加号添加 Artifact。
将Application Context改为 \。
Spring MVC入门笔记_第5张图片
返回Server,将更新设为页面或源代码发生变化就更新(热部署)。
可以修改端口,如80端口。
Spring MVC入门笔记_第6张图片
点击OK创建完成。
注:如果遇到404的问题可以参考这个解决方法。
关于Tomcat在本地启动没问题,在IDEA部署发生404的解决

2. Spring MVC 环境配置

1.Maven依赖spring-webmvc


    <repositories>
       <repository>
           <id>aliyunid>
           <name>aliyunname>
           <url>https://maven.aliyun.com/repository/publicurl>
       repository>
    repositories>

	<dependencies>
        <dependency>
            <groupId>org.springframeworkgroupId>
            <artifactId>spring-webmvcartifactId>
            <version>5.1.9.RELEASEversion>
        dependency>
    dependencies>

2.web.xml配置DispatcherServlet

<servlet>
        <servlet-name>springmvcservlet-name>
        
        <servlet-class>org.springframework.web.servlet.DispatcherServletservlet-class>
        
        <init-param>
            <param-name>contextConfigLocationparam-name>
            <param-value>classpath:applicationContext.xmlparam-value>
        init-param>
        
        <load-on-startup>0load-on-startup>
    servlet>
    <servlet-mapping>
        <servlet-name>springmvcservlet-name>
        
        <url-pattern>/url-pattern>
    servlet-mapping>
<url-pattern>/url-pattern>
/: 会匹配到/login这样的路径型url,不会匹配到模式为*.jsp这样的后缀型url
2、 <url-pattern>/*url-pattern>
/*:会匹配所有url(只匹配当前文件夹下文件,不匹配子文件夹下文件):路径型的和后缀型的url(包括/login,*.jsp,*.js和*.html等)

一般情况下DispatcherServlet只需要处理我们向后台服务器的请求,不需要处理静态页面等内容,所以,建议使用/。

3.配置applicationContext的mvc标记


<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mv="http://www.springframework.org/schema/mvc"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
            http://www.springframework.org/schema/beans/spring-beans.xsd
            http://www.springframework.org/schema/context
            http://www.springframework.org/schema/context/spring-context.xsd
            http://www.springframework.org/schema/mvc
            http://www.springframework.org/schema/mvc/spring-mvc.xsd">

    
    
    <context:component-scan base-package="com.imooc.springmvc">context:component-scan>
    
    <mvc:annotation-driven/>
   	
    <mvc:default-servlet-handler/>

4.开发Controller控制器
在src/main/java文件夹下创建包扫描的文件夹.
创建测试控制类。

package com.imooc.springmvc.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
public class TestController {
    @GetMapping("/t") //localhost/t
    @ResponseBody //直接向响应输出字符串数据,不跳转页面。把方法返回的结果直接写进http响应体中。
    public  String test(){
        return "SUCCESS";
    }
}

更新maven依赖
因为新添加了springmvc的maven依赖,所以要更新maven依赖。
Edit Configurations -> Deployment -> Edit Artifact -> 选中在Available Elements 的所有依赖 -> 点击 Put into /WEB-INF /lib.
Spring MVC入门笔记_第7张图片

之后访问http://localhost/t即可得到测试页面.
Spring MVC入门笔记_第8张图片

3. Spring MVC执行示意图Spring MVC入门笔记_第9张图片

4. URL Mapping URL映射

问题:处理业务的方法如何和URL绑定在一起
@RequestMapping - 通用绑定, 放在类上面为全局的方法都加上前缀,放在方法上面,不再区分get和post请求。
@GetMapping - 绑定Get请求
@PostMapping - 绑定Post请求
@RequestMapping 绑定指定的类型请求方法:
@RequestMapping(value=“/g”,method = RequestMethod.GET)。

package com.imooc.springmvc.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
@RequestMapping("/um") //放在类上面为全局的方法都加上前缀,放在方法上面,不再区分get和post请求。
public class URLMappingController {
    @GetMapping("/g")
    @ResponseBody
    public String getMapping(){
        return "This is get method.";

    }

    @PostMapping ("/p")
    @ResponseBody
    public String postMapping(){
        return "This is post method.";
    }

}

5. Controller方法接受请求参数

使用Controller方法参数接收
前端页面。

DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Titletitle>
head>
<body>
<form action="/um/p" method="post">
    <input name="username"><br/>
    <input name="password"><br/>
    <input type="submit" value="提交">
form>

body>
html>

处理业务用的Controller类

package com.imooc.springmvc.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;

@Controller
@RequestMapping("/um") //放在类上面为全局的方法都加上前缀,放在方法上面,不再区分get和post请求。
public class URLMappingController {
    @GetMapping("/g")
    @ResponseBody
    //Get请求中如果有不符合命名规范的参数可以使用@RequestParam()将不规范命名的参数注入后面的自定义参数中。
    public String getMapping(@RequestParam("user_name") String username){
        System.out.println("username:" + username);
        return "This is get method.";

    }

    @PostMapping ("/p")
    @ResponseBody
//    注:方法中的类型可以自动转换,如页面中的表单输入为字符串,
//    如果定义为public String postMapping(String username, Long password){},
//    则password参数自动转为Long类型。参数名一定要和前端页面中的表单参数名一样。
//    可能遇到的问题:如果页面上输入的数据带有非数字内容,可能会出现400转换错误,需要检查吧表单校验是否严谨。
    public String postMapping(String username, String password){
        System.out.println(username+":"+password);
        return "This is post method.";
    }

}

使用Java Bean接收数据
如果表单的参数比较多,则可以使用实体对象来接收。
首先准备一个实体类。

package com.imooc.springmvc.entity;

public class User {
    private String username;
    private Long password;

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public Long getPassword() {
        return password;
    }

    public void setPassword(Long password) {
        this.password = password;
    }
}

然后将接收的方法参数改为实体类,springmvc会自动找到这个实体类并根据类的参数赋值。

@PostMapping ("/p1")
    @ResponseBody
    public String postMappingBean(User user){
        System.out.println(user.getUsername()+":"+user.getPassword());
        return "This is Java Bean post method.";
    }

6. 接受表单复合数据

相对路径和绝对路径的区别。
Spring MVC入门笔记_第10张图片
对于表单的复合数据如checkbox,可以使用数组,列表来接收,比如下面这个表单:

DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>学员调查问卷title>
    <style>
        .container {
            position: absolute;
            border: 1px solid #cccccc;
            left: 50%;
            top: 50%;
            width: 400px;
            height: 600px;
            margin-left: -200px;
            margin-top: -300px;
            box-sizing: border-box;
            padding: 10px;
        }

        h2 {
            margin: 10px 0px;
            text-align: center;
        }

        h3 {
            margin: 10px 0px;
        }
    style>
head>
<body>
<div class="container">
    <h2>学员调查问卷h2>
    <form action="./apply" method="post">
        <h3>您的姓名h3>
        <input name="name" class="text" style="width: 150px">
        <h3>您正在学习的技术方向h3>
        <select name="course" style="width: 150px">
            <option value="java">Javaoption>
            <option value="h5">HTML5option>
            <option value="python">Pythonoption>
            <option value="php">PHPoption>
        select>
        <div>
            <h3>您的学习目的:h3>
            <input type="checkbox" name="purpose" value="1">就业找工作
            <input type="checkbox" name="purpose" value="2">工作要求
            <input type="checkbox" name="purpose" value="3">兴趣爱好
            <input type="checkbox" name="purpose" value="4">其他
        div>

        <h3>收货人h3>
        <input name="delivery.name" class="text" style="width: 150px">
        <h3>联系电话h3>
        <input name="delivery.mobile" class="text" style="width: 150px">
        <h3>收货地址h3>
        <input name="delivery.address" class="text" style="width: 150px">

        <div style="text-align: center;padding-top:10px">
            <input type="submit" value="提交" style="width:100px">
        div>
    form>

div>
body>
html>

可以用下面的几个方法进行接收:
注:如果在方法的参数列表里用List(默认为ArrrayList)接收数据,则需要在参数前面加上@RequestParam注解,如果是用实体类接收数据,实体类中的List属性则不用加上@RequestParam注解。
用Map接收数据也是。
如果有参数可能为空,需要设置默认值则可以使用下面的方法:
@RequestParam(value = “n”,defaultValue = “ANON”)。

package com.imooc.springmvc.controller;

import com.imooc.springmvc.entity.Form;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import java.util.List;
import java.util.Map;

@Controller
public class FormController {
//    @PostMapping("/apply")
    @ResponseBody
    public String apply(@RequestParam(value = "n",defaultValue = "ANON") String name, String course, Integer[] purpose){
        System.out.println(name);
        System.out.println(course);
        for (Integer p : purpose) {
            System.out.println(p);
        }
        return "SUCCESS";
    }

//    @PostMapping("/apply")
    @ResponseBody
    public String apply(String name, String course, @RequestParam List<Integer> purpose){
        System.out.println(name);
        System.out.println(course);
        for (Integer p : purpose) {
            System.out.println(p);
        }
        return "SUCCESS";
    }

//    @PostMapping("/apply")
    @ResponseBody
    public String apply(Form form){
        return "SUCCESS";
    }

}

实体类的定义如下:

package com.imooc.springmvc.entity;

import java.util.List;

public class Form {
    private String name;
    private String course;
    private List<Integer> purpose;
    private Delivery delivery = new Delivery();
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getCourse() {
        return course;
    }

    public void setCourse(String course) {
        this.course = course;
    }

    public List<Integer> getPurpose() {
        return purpose;
    }

    public void setPurpose(List<Integer> purpose) {
        this.purpose = purpose;
    }

    public Delivery getDelivery() {
        return delivery;
    }

    public void setDelivery(Delivery delivery) {
        this.delivery = delivery;
    }
}

注:Map也可以接收表单数据,但无法接收复合数据,如果接收复合数据则只会得到一个值,其他数据会丢失。

//    @PostMapping("/apply")
    @ResponseBody
    public String apply(@RequestParam Map map){
        System.out.println(map);
        return "SUCCESS";
    }

7. 关联对象赋值

如果我们想要在接收数据的实体类中引用另外一个实体类,则需要修改表单中的name属性,值应该为被引用的实体类对象在接收数据的实体类中的参数名.原本的参数名。
举个例子如下,接收数据的实体类如下:

package com.imooc.springmvc.entity;

import java.util.List;

public class Form {
    private String name;
    private String course;
    private List<Integer> purpose;
    private Delivery delivery = new Delivery();
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getCourse() {
        return course;
    }

    public void setCourse(String course) {
        this.course = course;
    }

    public List<Integer> getPurpose() {
        return purpose;
    }

    public void setPurpose(List<Integer> purpose) {
        this.purpose = purpose;
    }

    public Delivery getDelivery() {
        return delivery;
    }

    public void setDelivery(Delivery delivery) {
        this.delivery = delivery;
    }
}

被引用的实体类:

ackage com.imooc.springmvc.entity;

public class Delivery {
    private String name;
    private String address;
    private String mobile;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    public String getMobile() {
        return mobile;
    }

    public void setMobile(String mobile) {
        this.mobile = mobile;
    }
}

表单中的属性值为:

<h3>收货人h3>
        <input name="delivery.name" class="text" style="width: 150px">
        <h3>联系电话h3>
        <input name="delivery.mobile" class="text" style="width: 150px">
        <h3>收货地址h3>
        <input name="delivery.address" class="text" style="width: 150px">

使用注解将字符串转换为指定格式的额日期类型:

public String postMapping1(User user , String username ,@DateTimeFormat(pattern = "yyyy-MM-dd") Date createTime){
        return "

这是Post响应

"
; }

8. 解决中文乱码问题

对于Get方法,在8版本及以前的Tomcat找到安装文件夹下的conf目录中server.xml配置文件找到8080端口代码段进行修改

<Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443"/>

<Connector
port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443" URIEncoding="UTF-8"/>

对于Post方法,则需要在web.xml中配置过滤器

<filter>
        <filter-name>characterFilterfilter-name>
        <filter-class>org.springframework.web.filter.CharacterEncodingFilterfilter-class>
        <init-param>
            <param-name>encodingparam-name>
            <param-value>UTF-8param-value>
        init-param>
    filter>
    <filter-mapping>
        <filter-name>characterFilterfilter-name>
        <url-pattern>/*url-pattern>
    filter-mapping>

解决Response响应乱码-Spring项目的applicationContext.xml配置StringHttpMessageConverter

<mvc:annotation-driven conversion-service="conversionService">
        <mvc:message-converters>
            <bean class="org.springframework.http.converter.StringHttpMessageConverter">
                <property name="supportedMediaTypes">
                    <list>
                        <!-- response.setContentType("text/html;charset=utf-8") -->
                        <value>text/plain;charset=utf-8</value>
                        <value>text/html;charset=utf-8</value>
                    </list>
                </property>
            </bean>
        </mvc:message-converters>
    </mvc:annotation-driven>

9. 响应结果输出

注解 @ResponseBody
@ResponseBody - 产生响应文本
@ResponseBody直接产生响应体的数据,过程不涉及任何视图
@ResponseBody可产生标准字符串/JSON/XML等格式数据
@ResponseBody被StringHttpMessageConverter所影响

@GetMapping("/g")
@ResponseBody
public String getMapping(@RequestParam("manager_name") String managerName , Date createTime){
    System.out.println("managerName:"+managerName);
    return "This is get method";
    }

ModelAndView对象
ModelAndView对象是指"模型(数据)与视图(界面)”对象
通过ModelAndView可将包含数据对象与模板引警进行绑定
SpringMVC中默认的View是JSP也可以配置其他模板引擎
这个模式的设计理念是将模型(即生成数据的Controller部分)和视图(即页面如jsp部分)进行解耦(通过EL表达式传输数据),实现动态页面。

@GetMapping("/view")
    public ModelAndView showView(Integer userId){
//        ModelAndView mav = new ModelAndView("redirect:/view.jsp");
        ModelAndView mav = new ModelAndView();
        mav.setViewName("/um/view.jsp");
        User user = new User();
        if(userId == 1){
            user.setUsername("lily");
        }else if(userId == 2){
            user.setUsername("smith");
        }else if(userId == 3){
            user.setUsername("lina");
        }
        mav.addObject("u" , user);
        return mav;
    }
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <h1>I'm view page</h1>
    <hr>
    <h3>Username:${u.username}</h3>
</body>
</html>

mav.addObject()方法设置的属性默认存放在当前请求中
默认ModelAndView使用请求转发(forward)至页面
重定向使用 new ModelAndView(“redirect:/indexjsp”)
由于转发是将当前的请求发送给jsp页面,所以添加在mav.addObject()方法中的数据能用在jsp页面中。但是重定向是让服务器重新生成一个请求发送给jsp页面,所以mav.addObject()方法中的数据会丢失。
一种替代的模型和视图的方法例子:

//String与ModelMap
    //Controller方法返回String的情况
    //1. 方法被@ResponseBody描述,SpringMVC直接响应String字符串本身
    //2. 方法不存在@ResponseBody,则SpringMVC处理String指代的视图(页面)
    @GetMapping("/xxxx")
//    @ResponseBody
    public String showView1(Integer userId , ModelMap modelMap){
        String view = "/um/view.jsp";
        User user = new User();
        if(userId == 1){
            user.setUsername("lily");
        }else if(userId == 2){
            user.setUsername("smith");
        }else if(userId == 3){
            user.setUsername("lina");
        }
        modelMap.addAttribute("u", user);
        return view;
    }

10. SpringMVC整合Freemarker

  1. 在pom.xml中引入依赖(不要忘记手动更新artifact的依赖)
<dependency>
            <groupId>org.freemarkergroupId>
            <artifactId>freemarkerartifactId>
            <version>2.3.28version>
        dependency>
        <dependency>
            <groupId>org.springframeworkgroupId>
            <artifactId>spring-context-supportartifactId>
            <version>5.1.9.RELEASEversion>
        dependency>
  1. 在applicationContext.xml中配置freemarker

<bean id="ViewResolver" class="org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver">
		
        <property name="contentType" value="text/html;charset=utf-8"/>
        
        <property name="suffix" value=".ftl"/>
    bean>

    <bean id="freemarkerConfig" class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer">
        
        <property name="templateLoaderPath" value="/WEB-INF/ftl"/>
       	
        <property name="freemarkerSettings">
            <props>
            	
                <prop key="defaultEncoding">UTF-8prop>
            props>
        property>
    bean>

整合完成,创建Controller测试用类

package com.imooc.springmvc.controller;

import com.imooc.springmvc.entity.User;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

@Controller
@RequestMapping("/fm")
public class FreemarkerController {
    @GetMapping("/test")
    public ModelAndView showTest(){
        ModelAndView mav = new ModelAndView("/test");
        User user = new User();
        user.setUsername("andy");
        mav.addObject("u", user);
        return mav;
    }
}

创建test.ftl页面

<h1>${u.username}h1>

你可能感兴趣的:(JAVA基础知识学习笔记,spring,mvc,笔记)