SpringMVC入門案例 & 常用API使用演示

Dean_xiu發表於2020-11-27

SpringMVC入門案例

SpringMVC的建立方式有xml和配置類兩種方式
這裡只記錄實際應用中使用的方式搭建SpringMVC工程

檔案結構

在這裡插入圖片描述

步驟概述

  1. 因為採用父級工程和子工程的方式進行演示,所以此處只對父級pom.xml檔案進行修改,新增子工程需要的依賴包以及jdk版本
  2. 構建配置類WebConfig,掃描Controller層
  3. 編輯controller層,對頁面請求進行處理
  4. 構建啟動類,該啟動類繼承了AbstractAnnotationConfigDispatcherServletInitializer,並通過其下的三個函式對配置類進行解析
  5. 編寫需要的前端頁面

步驟實現

  • 父級pom.xml的修改
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>com.dean</groupId>
  <artifactId>SpringMvcAPi</artifactId>
  <version>1.0-SNAPSHOT</version>
  <modules>
    <module>mvc-viewResolution</module>
  </modules>
  <packaging>pom</packaging>

  <name>SpringMvcAPi</name>
  <url>http://maven.apache.org</url>

  <!--1、修改父級的pom.xml檔案 只需要修改properties和dependencies節點的內容-->
  <!--修改版本-->
  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>1.8</maven.compiler.source>
    <maven.compiler.target>1.8</maven.compiler.target>
  </properties>

  <!--新增所有子工程可能用到的依賴包-->
  <dependencies>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-core</artifactId>
      <version>5.3.0</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>5.3.0</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-webmvc</artifactId>
      <version>5.3.0</version>
    </dependency>
    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>javax.servlet-api</artifactId>
      <version>3.1.0</version>
    </dependency>
  </dependencies>
</project>
  • 構建web配置類WebConfig
@ComponentScan("com.dean.controller")
public class WebConfig {
}
  • 編輯前端控制器 controller層
@Controller   //將bean注入到Spring容器
@RequestMapping("/user")     //配置請求對映,在請求時用來區分不同的controller
public class UserController {
    //返回頁面有兩種寫法
    //1、返回頁面的檔名,作為字串,框架會呼叫ModelAndView進行返回檢視
    //實際請求拼接了/user和/hello 從而找到hello方法
    @RequestMapping("/hello")
    public String hello()
    {
        return "/hello.jsp";
    }

    //2、直接設定返回值為ModelAndView
    @RequestMapping("/view")
    public ModelAndView view()
    {
        return new ModelAndView("/view.jsp");
    }
}
  • 編寫啟動類
public class WebMvcInit extends AbstractAnnotationConfigDispatcherServletInitializer {
    //整合Spring使用的,這裡暫不配置
    @Override
    protected Class<?>[] getRootConfigClasses() {
        return new Class[0];
    }

    //指定SpringMvc的配置類
    @Override
    protected Class<?>[] getServletConfigClasses() {
        return new Class[]{WebConfig.class};
    }

    //配置請求對映,這裡配置所有請求,即/
    @Override
    protected String[] getServletMappings() {
        return new String[]{"/"};
    }
}
  • 編寫前端頁面 index(主頁)hello(/user/hello請求頁面)view(/user/view請求頁面)
    index
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <%--5、編寫前端頁面  index主頁--%>
    <title>主頁</title>
</head>
<body>
<h1>
    <a href="/user/hello">hello</a>
</h1>
<h1>
    <a href="/user/view">view</a>
</h1>
</body>
</html>

hello

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <%--5、編寫前端頁面 hello--%>
    <title>Hello</title>
</head>
<body>
<h1>Hello</h1>
</body>
</html>

view

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <%--5、編寫前端頁面 view--%>
    <title>View</title>
</head>
<body>
<h1>View</h1>
</body>
</html>

常用API

檢視解析

檢視解析實質上是利用對方法的後置攔截,在返回檢視時進行配置檢視解析器,使得在controller層返回引數的時候,只需要返回檢視名稱,而無需返回字尾名等

具體實現

在上述專案的WebConfig類中注入InternalResourceViewResolver

@ComponentScan("com.dean.controller")
public class WebConfig {
    //新增檢視解析器
    @Bean
    public InternalResourceViewResolver viewResolver()
    {
        InternalResourceViewResolver viewResolver=new InternalResourceViewResolver();
        //設定檢視路徑字首
        viewResolver.setPrefix("/");
        //設定檢視路徑的字尾
        viewResolver.setSuffix(".jsp");
        return viewResolver;
    }
}

controller層的程式碼返回值的更改

@Controller   //將bean注入到Spring容器
@RequestMapping("/user")     //配置請求對映,在請求時用來區分不同的controller
public class UserController {
    @RequestMapping("/hello")
    public String hello()
    {
        //配置檢視解析器之前
        //return "/hello.jsp";

        //配置檢視解析器後
        return "hello";
    }

    @RequestMapping("/view")
    public ModelAndView view()
    {
        //配置檢視解析器之前
        //return new ModelAndView("/view.jsp");

        //配置檢視解析器之後
        return new ModelAndView("view");
    }

}

檢視解析器會使springmvc獲取到controller方法的返回值,然後與字首字尾拼接得到完整的檢視路徑

但上述的檢視解析器配置的是放在根路徑下,從外部可以直接訪問,在安全性上較差,servlet對此有所改進,將檢視放在WEB-INF目錄下,在該目錄下的檢視只能從內部訪問,而無法從外部直接訪問
改進後的檔案結構如下:
在這裡插入圖片描述

改進後的檢視解析器程式碼如下:

@ComponentScan("com.dean.controller")
public class WebConfig {
    //新增檢視解析器
    @Bean
    public InternalResourceViewResolver viewResolver()
    {
        InternalResourceViewResolver viewResolver=
        				new InternalResourceViewResolver();
        //直接放在根目錄下不安全,改進版
        //設定檢視路徑字首
        viewResolver.setPrefix("/WEB-INF/view/");
        //設定檢視路徑字尾
        viewResolver.setSuffix(".jsp");
        return viewResolver;
    }
}

引數傳遞(等同於servlet中的request.getAttribute())

在Servlet中引數的傳遞通過request.getAttribute()方法,返回值是string,使用時需要自行轉換
springMvc簡化了這一過程,具有自動引數轉化功能

基本資料型別 & String型別

主要核心程式碼在Controller層

@Controller
@RequestMapping("/user")
public class UserController {
    //value是請求對映
    //method是請求方法  類似servlet的doPost方法
    @RequestMapping(value = "/addUser",method = RequestMethod.POST)
    public ModelAndView addUser(
            //@RequestParam 說明該引數是請求引數
            //name 指明引數名稱 與表單中標籤的名稱一致   未指定時預設與形參變數名相同
            //required 確定引數是否必須傳遞 未指定時預設為true
            //defaultValue 當引數不是一定要傳遞時,可以設定引數的預設值
            @RequestParam(name="username",required = true) String name,
            @RequestParam(required = false,defaultValue = "21") Integer age,
            String phone
    )
    {
        System.out.println(name+"\t"+age+"\t"+phone);
        return new ModelAndView("success");
    }
}

請求頁面使用表單完成

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>主頁</title>
</head>
<body>
<h1>基本資料型別 & String</h1>
<form action="/user/addUser" method="post">
    <p>
        <label for="username">username:</label>
        <input type="text" id="username" name="username">
    </p>

    <p>
        <label for="age">age:</label>
        <input type="text" id="age" name="age">
    </p>

    <p>
        <label for="phone">phone:</label>
        <input type="text" id="phone" name="phone">
    </p>
    <button type="submit">add</button>
</form>
</body>
</html>

物件型別(自動裝箱)

當傳遞的引數是自定義的物件型別時,SpringMVC採用了自動裝箱技術,會去自動匹配POJO型別(pojo是簡單java物件,即javaBean,只是叫了不同的名字)
物件型別Pet

public class Pet {
    private String name;

    public String getName() {
        return name;
    }

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

    @Override
    public String toString() {
        return "Pet{" +
                "name='" + name + '\'' +
                '}';
    }
}

Person類

public class Person {
    private String name;
    private Integer age;
    private Pet pet;

    public String getName() {
        return name;
    }

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

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public Pet getPet() {
        return pet;
    }

    public void setPet(Pet pet) {
        this.pet = pet;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", pet=" + pet +
                '}';
    }
}

Controller

@Controller
@RequestMapping("/user")
public class UserController {
    //物件型別自動裝箱
    @RequestMapping(value = "/addPerson",method = RequestMethod.POST)
    public ModelAndView addPerson(
            /*
            會去自動找Person類,呼叫setter方法
             */
            Person person
    )
    {
        System.out.println(person);
        return new ModelAndView("success");
    }

}

前端頁面

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>主頁</title>
</head>
<body>
<h1>物件型別 自動裝箱</h1>
<form action="/user/addPerson" method="post">
    <p>
        <label for="name">Person-name:</label>
        <input type="text" name="name" id="name">
    </p>

    <p>
        <label for="age">Age:</label>
        <input type="text" name="age" id="age">
    </p>

    <p>
        <label for="pet-name">Pet-name:</label>
        <input type="text" name="pet.name" id="pet-name">
    </p>

    <button type="submit">add</button>
</form>
</body>
</html>

日期型別

針對日期型別,主要依靠兩個註解
@EnableWebMvc 和 @DateTimeFormat
兩步搞定
1、在WebConfig上新增註解@EnableWebMvc
2、在形參或成員變數上新增註解@DateTimeFormat
具體程式碼如下:
WebConfig

@ComponentScan("com.dean.controller")
@EnableWebMvc    //開啟轉換器 便於將表單提交的String型別的資料轉換為Date型別
public class WebConfig {
    @Bean
    public InternalResourceViewResolver viewResolver()
    {
        InternalResourceViewResolver resolver=new InternalResourceViewResolver();
        resolver.setPrefix("/WEB-INF/view/");
        resolver.setSuffix(".jsp");
        return resolver;
    }
}

UserController

@Controller
@RequestMapping("/user")
public class UserController {
    @RequestMapping(value = "/date",method = RequestMethod.GET)
    public ModelAndView getDate(@DateTimeFormat(pattern = "yyyy/MM/dd HH:mm:ss") Date date)
    {
        System.out.println(date);
        return new ModelAndView("success");
    }

}

前端頁面

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>主頁</title>
</head>
<body>
<h1>日期型別</h1>
<form action="/user/date" method="get">
    <p>
        <label for="date">Date:</label>
        <input type="text" id="date" name="date">
    </p>
    <button type="submit">submit</button>
</form>
</body>
</html>

引數亂碼

在web的啟動類處新增過濾器Filter進行編碼設定
在這裡插入圖片描述

返回引數(等同於servlet中的request.setAttribute(“key”,value))

在servlet裡,通過request.setAttribute()在後端設定引數,在前端頁面通過ER表示式獲取引數的值顯示在介面上

但在SpringMVC中有非常多的方式返回引數,然後在前端頁面通過ER表示式進行渲染資料

方式1:ModelAndView+ModelAndView.addObject()

程式碼如下:
前端頁面:

<%@ page contentType="text/html;charset=UTF-8" language="java" isErrorPage="false" %>
<%--使用ER表示式 引入taglib--%>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
    <%--6、前端頁面  返回頁面--%>
    <title>返回頁面</title>
</head>
<body>
    <table>
        <thead>
        <tr>
            <th>id</th>
            <th>name</th>
            <th>age</th>
        </tr>
        </thead>
        <tbody>
        <c:forEach var="user" items="${users}">
            <tr>
                <td>${user.id}</td>
                <td>${user.name}</td>
                <td>${user.age}</td>
            </tr>
        </c:forEach>
        </tbody>
    </table>
</body>
</html>

前端控制器:

@Controller
@RequestMapping("/user")
public class UserController {
    //addObject方式
    @RequestMapping("/find-one")
    public ModelAndView findOne()
    {
        //使用list模擬資料庫資料
        List<User> users=new ArrayList<>();
        users.add(new User("1", "小海", 22));
        users.add(new User("2", "小白", 18));
        users.add(new User("3", "zz", 26));
        users.add(new User("4","鯨魚",28));

        ModelAndView mv=new ModelAndView();
        //相當於request.setAttribute("users",users);
        mv.addObject("users",users);
        //設定返回檢視
        mv.setViewName("userView");
        return mv;
    }
}

方式2:ModelAndView+Model.addAttribute()

前端頁面與上述一致
前端控制器程式碼如下:

@Controller
@RequestMapping("/user")
public class UserController {
    //addAtribute方式
    @RequestMapping("/find-two")
    public ModelAndView findTwo(Model model)
    {
        //使用list模擬資料庫資料
        List<User> users=new ArrayList<>();
        users.add(new User("1", "小海", 22));
        users.add(new User("2", "小白", 18));
        users.add(new User("3", "zz", 26));
        users.add(new User("4","鯨魚",28));

        //依然是request.setAttribute("users",users);
        model.addAttribute("users",users);
        //返回檢視
        return new ModelAndView("userView","model",model);
    }

}

方式3:ModelAndView+Map

前端頁面與上述一致
前端控制器程式碼如下:

@Controller
@RequestMapping("/user")
public class UserController {
  
    //ModelAndView+Map
    @RequestMapping("/find-three")
    public ModelAndView findThree(Map<String, Object> map)
    {
        //使用list模擬資料庫資料
        List<User> users=new ArrayList<>();
        users.add(new User("1", "小海", 22));
        users.add(new User("2", "小白", 18));
        users.add(new User("3", "zz", 26));
        users.add(new User("4","鯨魚",28));
        //將資料放入map
        map.put("users",users);

        //返回檢視
        return new ModelAndView("userView",map);
    }

}

方式4:String+Map

前端頁面與之前一致
前端控制器程式碼如下:

@Controller
@RequestMapping("/user")
public class UserController {
  
   //String+Map
    @RequestMapping("/find-four")
    public String findFour(Map<String, Object> model)
    {
        //使用list模擬資料庫資料
        List<User> users=new ArrayList<>();
        users.add(new User("1", "小海", 22));
        users.add(new User("2", "小白", 18));
        users.add(new User("3", "zz", 26));
        users.add(new User("4","鯨魚",28));
        //將資料放入map
        model.put("users",users);

        return "userView";
    }

}

方式5:Web原生物件:傳遞形參(HttpServletRequest,HttpServletResponse)

前端頁面程式碼同上
前端控制器程式碼如下:

@Controller
@RequestMapping("/user")
public class UserController {
   //Web原生物件 傳參
    @RequestMapping("/find-web")
    public String findWeb(HttpServletRequest req, HttpServletResponse resp)
    {
        //使用list模擬資料庫資料
        List<User> users=new ArrayList<>();
        users.add(new User("1", "小海", 22));
        users.add(new User("2", "小白", 18));
        users.add(new User("3", "週週", 26));
        users.add(new User("4","鯨魚",28));

        //使用Web原生物件HttpServletRequest設定引數
        req.setAttribute("users",users);
        return "userView";
    }
}

方式6:Web原生物件:建立ServletRequestAttributes

通過自行建立ServletRequestAttributes物件獲取原生引數
前端頁面程式碼同上
前端控制器程式碼如下:

@Controller
@RequestMapping("/user")
public class UserController {
   //建立ServletRequestAttributes物件
    @RequestMapping("/webObj")
    public String webObj()
    {
        //使用list模擬資料庫資料
        List<User> users=new ArrayList<>();
        users.add(new User("1", "週週", 26));
        users.add(new User("2","鯨魚",28));
        users.add(new User("3", "小海", 22));
        users.add(new User("4", "小白", 18));


        ServletRequestAttributes requestAttributes= (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        //通過ServletRequestAttributes例項獲取引數物件
        //ServletRequestAttributes可以獲取HttpServletRequest HttpServletResponse HttpSession物件
        HttpServletRequest req = requestAttributes.getRequest();
        //通過request設定引數
        req.setAttribute("users",users);

        //返回檢視
        return "userView";
    }
}

JSON資料處理

核心步驟

  • pom.xml檔案中新增json的依賴包
  • WebConfig中新增@EnableWebMvc 並配置不要將靜態資源的載入當作請求
  • 在controller層新增註解 @ResponseBody 並編寫方法進行傳遞資料
  • 在前端頁面引入jquery並編寫Ajax請求

具體實現

  • pom.xml新增的依賴包
<dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-core</artifactId>
            <version>2.12.0-rc2</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.12.0-rc2</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-annotations</artifactId>
            <version>2.12.0-rc2</version>
        </dependency>
  • WebConfig程式碼
@ComponentScan("com.dean.controller")
@EnableWebMvc  //一定要新增
public class WebConfig implements WebMvcConfigurer {
    //新增預設請求的檢視返回  可以沒有
    //即請求/時 返回index.html頁面
 @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        registry.addViewController("/").setViewName("index");
    }

    //配置靜態資源
    //使載入靜態資源時,不被當作請求處理
    @Override
    public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
        configurer.enable();
    }
}
  • Controller層程式碼
@Controller
@RequestMapping("/user")
public class UserController {
    @RequestMapping(value = "/findUser",method = RequestMethod.POST)
    @ResponseBody   //幫助使用HttpServletResponse返回資料
    //採用形參傳參,前端頁面設定的引數將會傳到後端
    public List<User>  findUser(User user)
    {
        //前端Ajax請求的資料
        System.out.println(user);
        //後端傳送的資料
        List<User> users=new ArrayList<>();
        users.add(new User("1", "週週", 26));
        users.add(new User("2", "小海", 22));
        users.add(new User("3", "小白", 18));

        return users;
    }
}

  • 前端頁面
    前端頁面會返回一個包含後端傳入資料的表格
<!DOCTYPE html>
<html lang="en">
<head>
    <!--6、編寫前端頁面-->
    <meta charset="UTF-8">
    <title>主頁</title>
    <!--引入jquery-->
    <script src="/static/jquery-2.1.1.js"></script>
</head>
<body>
<h1>Html</h1>
<button onclick=findUser()>findUser</button>
<table id="table">
</table>
<script>
    function findUser() {
        $.ajax({
            url:"/user/findUser",
            method:"post",
            dataType:"json",
            data:{id:4,name:"鯨魚",age:22},
            success:function (data) {
                //$('#table').empty();  //清空原表格
                $('#table').append("<tr><th>id</th><th>name</th><th>age</th></tr>");
                // let html="<tr><th>id</th><th>name</th><th>age</th></tr>";
                $.each(data,function (i,item) {
                    html="<tr>" +
                            "<td>"+item['id']+"</td>"+
                            "<td>"+item['name']+"</td>"+
                            "<td>"+item['age']+"</td>"+
                        "</tr>"
                    $('#table').append(html);
                });
                // $('#table').html(html);

            }
        })
    }
</script>
</body>
</html>

RestFul請求

將前後端分離,在處理請求時,後端只返回資料(即只提供資源)給前端頁面,只渲染資料,不再渲染標籤
前端和後端設定不同的埠號,部署在不同的伺服器上
RestFul的狀態轉換(GET POST Delete Put)對應著對於資源的CRUD操作
RestFul中有一個重要的概念:冪等性(即無論請求多少次,資源都是相同的)

核心步驟

  • 在專案的pom.xml中新增依賴
  • 編寫Spring MVC的配置類 (核心 @EnableWebMvc
  • 編寫前端控制器 UserController,開啟同源策略,編寫請求 (核心 **@CrossOrigin ** @GetMapping @PostMapping @PutMapping @DeleteMapping@RequestMapping+@ResponseBody )
  • 模擬資料,設計響應資料的格式
  • 編寫啟動類
  • 使用WebStorm編寫前端頁面
  • 將前端頁面部署到nginx上

具體實現

後端
檔案結構
在這裡插入圖片描述


  • 修改pom.xml
    在這裡插入圖片描述
  • SpringMvc配置類
@ComponentScan("com.dean.controller")
@EnableWebMvc
public class WebConfig {
}
  • 前端控制器
    新增的註釋
    在這裡插入圖片描述

Get請求
@Controller+@ResponseBody版本

//Get請求
    //url: /user/1 (查詢id=1的使用者資訊)
    //響應型別: application/json
    //返回資料:{"id":1,"name":"string","age":int}
      @RequestMapping(value = "{id}",method = RequestMethod.GET)
      @ResponseBody
    public ResultEntity getUserById(@PathVariable(value = "id") String id)
    {
        //從資料庫請求資料
        User user=users.get(id);
        return new ResultEntity(200,"ok",true,user);
    }

@RestController版本

//Get請求
    //url: /user/1 (查詢id=1的使用者資訊)
    //響應型別: application/json
    //返回資料:{"id":1,"name":"string","age":int}
    @GetMapping("{id}")  //等同於@RequestMapping(value = "{id}",method = RequestMethod.GET)
    public ResultEntity getUserById(@PathVariable(value = "id") String id)
    {
        //從資料庫請求資料
        User user=users.get(id);
        return new ResultEntity(200,"ok",true,user);
    }

Post請求
@Controller+@ResponseBody版本

//Post請求
    //url: /user   新增一個使用者
    //引數型別:application/json
    //引數: {"id":1,"name":"string","age":int} 自動裝箱
    //響應型別:application/json
    //響應資料:{}
    @RequestMapping(method = RequestMethod.POST)
    @ResponseBody
    public ResultEntity addUser(@RequestBody User user)
    {
        users.put(user.getId(),user);
        System.out.println(user);
        return new ResultEntity(200,"ok",true,null);
    }

@RestController版本

//Post請求
    //url: /user   新增一個使用者
    //引數型別:application/json
    //引數: {"id":1,"name":"string","age":int} 自動裝箱
    //響應型別:application/json
    //響應資料:{}
    @PostMapping
    public ResultEntity addUser(@RequestBody User user)
    {
        users.put(user.getId(),user);
        System.out.println(user);
        return new ResultEntity(200,"ok",true,null);
    }

Put請求
@Controller+@ResponseBody版本

//Put請求
    //url: /user/1  修改id=1的使用者資訊
    //引數型別:application/json
    //引數格式:{"name":"string","age":int}
    //響應型別:application/json
    //響應資料:{}
    @RequestMapping(value = "{id}",method = RequestMethod.PUT)
    @ResponseBody
    public ResultEntity updateUser(@PathVariable String id,@RequestBody User user)
    {
        user.setId(id);
        users.put(id,user);
        System.out.println(users);
        return new ResultEntity(200,"update success",true,"{}");
    }

@RestController版本

//Put請求
    //url: /user/1  修改id=1的使用者資訊
    //引數型別:application/json
    //引數格式:{"name":"string","age":int}
    //響應型別:application/json
    //響應資料:{}
    @PutMapping("{id}")
    public ResultEntity updateUser(@PathVariable String id,@RequestBody User user)
    {
        user.setId(id);
        users.put(id,user);
        System.out.println(users);
        return new ResultEntity(200,"update success",true,"{}");
    }

Delete請求
@Controller+@ResponseBody版本

//Delete請求
    //url: /user/1 刪除id=1的使用者
    //響應型別:application/json
    //響應資料:{}
    @RequestMapping(value = "{id}",method = RequestMethod.DELETE)
    @ResponseBody
    public ResultEntity delUser(@PathVariable(value = "id") String uid)
    {
        users.remove(uid);
        return new ResultEntity(200,"delete success",true,"{}");
    }

@RestController版本

//Delete請求
    //url: /user/1 刪除id=1的使用者
    //響應型別:application/json
    //響應資料:{}
    @DeleteMapping("{id}") //等同於@RequestMapping(value = "{id}",method = RequestMethod.DELETE)
    public ResultEntity delUser(@PathVariable(value = "id") String uid)
    {
        users.remove(uid);
        return new ResultEntity(200,"delete success",true,"{}");
    }
  • 模擬資料User 設計響應資料格式
    User
public class User {
    private String id;
    private String name;
    private Integer age;

    public User() {
    }

    public User(String id, String name, Integer age) {
        this.id = id;
        this.name = name;
        this.age = age;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

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

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "User{" +
                "id='" + id + '\'' +
                ", name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

響應資料格式(仿照http的響應資料格式)

/**
 * {
 *     "code":200,  狀態碼
 *     "message":"string",  提示資訊
 *     "flag":"boolean",   執行狀況
 *     "data":"object(json)"  資料
 * }
 */
public class
ResultEntity {
    private Integer code;
    private String message;
    private Boolean flag;
    private Object data;

    public ResultEntity() {

    }

    public ResultEntity(Integer code, String message, Boolean flag, Object data) {
        this.code = code;
        this.message = message;
        this.flag = flag;
        this.data = data;
    }

    public Integer getCode() {
        return code;
    }

    public void setCode(Integer code) {
        this.code = code;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

    public Boolean getFlag() {
        return flag;
    }

    public void setFlag(Boolean flag) {
        this.flag = flag;
    }

    public Object getData() {
        return data;
    }

    public void setData(Object data) {
        this.data = data;
    }
}
  • 啟動類
public class WebServerInit extends AbstractAnnotationConfigDispatcherServletInitializer {
    @Override
    protected Class<?>[] getRootConfigClasses() {
        return new Class[0];
    }

    @Override
    protected Class<?>[] getServletConfigClasses() {
        return new Class[]{WebConfig.class};
    }

    @Override
    protected String[] getServletMappings() {
        return new String[]{"/"};
    }
}

前端

  • 引入vue.js和jquery.js
    在這裡插入圖片描述
  • 編寫前端介面
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>主頁</title>
    <!--引入jquery和vue-->
    <script src="./static/vue.js"></script>
    <script src="./static/jquery-2.1.1.js"></script>
</head>
<body>
<div id="app">
    <!--顯示所有使用者-->
    <table style="width: 500px;text-align: center;border-color: cornflowerblue" border="1">
        <thead>
        <tr>
            <th>id</th>
            <th>name</th>
            <th>age</th>
        </tr>
        </thead>
        <tbody>
        <tr v-for="user in users" :key="user.id">
            <td>{{user.id}}</td>
            <td>{{user.name}}</td>
            <td>{{user.age }}</td>
        </tr>
        </tbody>
    </table>
    <!--新增使用者-->
    <div id="add-user">
        <p>
            <label for="add-user-id">id:</label>
            <input type="text" id="add-user-id" v-model="addUser.id">
        </p>
        <p>
            <label for="add-user-name">name:</label>
            <input type="text" id="add-user-name" v-model="addUser.name">
        </p>
        <p>
            <label for="add-user-age">age:</label>
            <input type="text" id="add-user-age" v-model="addUser.age">
        </p>
        <button @click="_addUser()">addUser</button>
        <button @click="_updateUser()">updateUser</button>
    </div>
    <hr>
    <p>
        <label for="del-user-id">id:</label>
        <input type="text" id="del-user-id" v-model="addUser.id">
    </p>
    <button @click="_deleteUser">deleteUser</button>
</div>
<script>
    let vm=new Vue({
        el:"#app",
        data:{
            users:[],
            addUser:{
                id:"",
                name:"",
                age:""
            }
        },
        //生命鉤子
        created(){
            //查詢所有使用者
             this._findAllUsers();
        },
        methods:{
            //查詢所有使用者
            _findAllUsers(){
                let this_=this;
                //編寫ajax請求
                $.ajax({
                    url:"http://localhost:8090/user/",  //請求url
                    method:"get",
                    dataType:"json",   //返回資料格式
                    contentType:"application/json", //網頁檔案的型別和網頁編碼格式
                    success:function (resp) {
                        this_.users=resp.data;
                    }
                })
                return null;
            },

            //新增使用者
            _addUser(){
                let this_=this;
                //編寫ajax請求
                $.ajax({
                    url:"http://localhost:8090/user/",
                    method:"post",
                    data:JSON.stringify(this_.addUser),  //將引數物件轉換為Json格式
                    dataType:"json",
                    contentType:"application/json",
                    success:function (resp) {
                        this_._findAllUsers(); //重新整理頁面
                    }
                })
            },

            //修改使用者
            _updateUser(){
                let id=this.addUser.id;
                let user={
                    name:this.addUser.name,
                    age:this.addUser.age
                }
                let this_=this;
                //編寫ajax請求
                $.ajax({
                    url:"http://localhost:8090/user/"+id,
                    method:"put",
                    data:JSON.stringify(user),  //將引數物件轉換為Json格式
                    dataType:"json",
                    contentType:"application/json",
                    success:function (resp) {
                        this_._findAllUsers(); //重新整理頁面
                    }
                })
            },

            //刪除使用者
            _deleteUser()
            {
                let id=this.addUser.id;
                let this_=this;
                //編寫ajax請求
                $.ajax({
                    url:"http://localhost:8090/user/"+id,
                    method:"delete",
                    data:JSON.stringify(this_.addUser),  //將引數物件轉換為Json格式
                    dataType:"json",
                    contentType:"application/json",
                    success:function (resp) {
                        this_._findAllUsers(); //重新整理頁面
                    }
                })
            }
        }
    })
</script>
</body>
</html>
  • 將頁面部署在nginx上
    即將頁面和static檔案複製在nginx的html資料夾裡,刪除原有的index.html檔案

統一異常處理

核心步驟

  • controller裡模擬丟擲異常
  • 編寫統一異常處理器CustomException
  • WebConfig(配置類),WebServerInit(啟動類)和之前一致

具體實現

  • Controller
@Controller
@RequestMapping("user")
public class UserController {
    @RequestMapping("main")
    public ModelAndView getMain(String name, Model model)
    {
        if("admin".equals(name))
        {
        	//模擬丟擲異常
            throw new RuntimeException("不能使用admin登入");
        }
        model.addAttribute("name",name);
        return new ModelAndView("main");
    }
}
  • 統一異常處理器CustomException
@ControllerAdvice
public class CustomException {
    //指定處理RuntimeException類的異常
    @ExceptionHandler(RuntimeException.class)
    public ModelAndView exception (Exception e, Model model)
    {
        System.out.println(e.getMessage());
        model.addAttribute("message",e.getMessage());
        return new ModelAndView("error");
    }

}

攔截器

Filter:過濾器 過濾的是url
intercepter:攔截器 面向方法的代理模式
主要是WebConfig和自定義的攔截器UserInterceptor

  • WebConfig
@ComponentScan("com.dean.controller")
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
    //新增檢視解析器
    @Bean
    public InternalResourceViewResolver viewResolver()
    {
        InternalResourceViewResolver viewResolver=new InternalResourceViewResolver();
        viewResolver.setPrefix("/WEB-INF/view/");
        viewResolver.setSuffix(".jsp");
        return viewResolver;
    }

    //配置靜態資源
    //相當於xml中的<mvc:default-servlet-handler>
    @Override
    public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
        configurer.enable();
    }


    //新增攔截器
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        //建立一個自定義的攔截器,加入容器
        registry.addInterceptor(new UserInterceptor());
    }
}

  • UserInterceptor
public class UserInterceptor implements HandlerInterceptor {

    //controller目標方法之前執行
    //適合做許可權的控制
    //形參Object handler實際指的是目標方法物件
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        HandlerMethod method= (HandlerMethod) handler;
        //method.getMethod().getName() 獲取到目標方法名
        System.out.println("目標方法執行前"+method.getMethod().getName());
        return true;
    }

    //controller目標方法成功執行之後執行
    //適合做日誌的管理
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        //modelAndView.getViewName()  獲取到返回的頁面名
        System.out.println("目標方法成功執行之後"+modelAndView.getViewName());
    }

    //最終方法,目標方法執行結束後(不論是否丟擲異常)
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        //ex.getMessage() 獲取到異常資訊
        System.out.println("目標方法執行之後"+ex.getMessage());
    }
}

Struts2

SpringMvc是基於方法開發的,較快,通過形參傳參,可以進行單例開發
Struts2是基於類開發的,較慢,通過類的成員變數傳參,無法進行單例開發

雖然很少有人用,但瞭解還是要了解的

核心步驟

  • pom.xml中新增依賴
  • 編寫配置類web.xml
  • 編寫核心類Action
  • 編寫核心檔案,配置請求返回檢視,struts.xml
  • 編寫前端頁面

具體實現

  • pom.xml中新增依賴
    在這裡插入圖片描述

  • 編寫配置類web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
                      http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
         version="3.1">
    <filter>
        <filter-name>struts2</filter-name>
        <filter-class>org.apache.struts2.dispatcher.filter.StrutsPrepareAndExecuteFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>struts2</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
</web-app>

  • 編寫核心類Action
public class UserAction {
    //基於類的程式設計 引數通過成員變數傳遞
    public String message;

    public void setMessage(String message) {
        this.message = message;
    }

    public String hello()
    {
        System.out.println(message);
        return "SUCCESS";
    }

    public String login()
    {
        if("admin".equals(message))
            return "ERROR";
        return "SUCCESS";
    }

}

  • 編寫核心檔案,配置請求返回檢視,struts.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.1//EN"
        "http://struts.apache.org/dtds/struts-2.1.dtd">
<struts>
    <!-- 請求引數的編碼方式 -->
    <constant name="struts.i18n.encoding" value="utf-8"/>
    <package name="USER" extends="struts-default" namespace="/user"> <!--請求由namespace和name拼接組成-->
        <action name="hello" class="com.dean.action.UserAction" method="hello">  <!--和action中的方法對應-->
            <result name="SUCCESS">/main.jsp</result>   <!--配置返回頁面-->
        </action>
        <action name="login" class="com.dean.action.UserAction" method="login">
            <result name="SUCCESS">/main.jsp</result>
            <result name="ERROR">/error.jsp</result>
        </action>
    </package>
</struts>    
  • 編寫前端頁面
    index首頁
    在這裡插入圖片描述
    成功返回頁面
    在這裡插入圖片描述
    發生錯誤後返回的頁面
    在這裡插入圖片描述

相關文章