主頁 > 後端開發 > ??最后的大爆發??五萬字總結SpringMVC教程——三部曲封神之作(建議收藏)

??最后的大爆發??五萬字總結SpringMVC教程——三部曲封神之作(建議收藏)

2021-10-09 08:23:49 後端開發

在這里插入圖片描述

文章目錄

  • 前言
  • 1. Spring MVC 概述
    • 2.1 Spring MVC是什么
    • 1.0 Spring MVC處理流程
  • 2. 入門案例:查詢詳情 ( xml)
    • 3.1 需求說明
    • 2.1 思路分析
    • 2.2 實作步驟
      • 2.2.1 拷貝組態檔相關代碼
      • 2.2.2 創建java類和jsp檔案
  • 3. 入門查詢:查詢所有(無xml)
    • 3.2 需求說明
    • 3.1 思路分析
    • 3.2 步驟實作
      • 3.2.1 拷貝pom檔案,創建MVCConfig和WebInitializer類
      • 3.2.2 創建HelloController和show01.jsp
  • 4. SSM整合:改造UMS
    • 4.1 搭建環境
      • 4.0.1 創建專案、 拷貝pom檔案
      • 4.0.2 拷貝UMS頁面
      • 4.0.3 組態檔
      • 4.0.4 初始化資料庫和表
      • 4.0.5 創建JavaBean
    • 4.1 撰寫功能:dao、service、web、jsp頁面
      • 4.1.1 撰寫mapper介面(dao)
      • 4.1.2 撰寫service介面
      • 4.1.3 撰寫service實作類
      • 4.1.4 撰寫Controller
      • 4.1.5 撰寫jsp
    • 4.2 撰寫配置類
      • 4.2.1 spring配置類
      • 4.2.2 mybatis配置類
      • 4.2.3 spring mvc 配置類【無內容】
      • 4.2.4 web啟動配置類【新內容】
    • 4.3 測驗
  • 5. 視圖 決議器
    • 5.1 分析
    • 5.2 修改代碼
      • 5.2.1 撰寫控制器
      • 5.2.2 配置視圖決議器
  • 6. SSM整合:改造UMS(添加視圖決議器)
  • 7. 引數 系結
    • 7.1 簡單資料型別
      • 7.1.1 支持的資料型別
      • 7.1.2 @RequestParam
    • 7.2 系結POJO型別
    • 7.3 POST中文亂碼
    • 7.4 系結包裝POJO
    • 7.5 自定義引數系結
    • 7.6 系結陣列
    • 7.7 表單資料系結到List
  • 8. @RequestMapping
    • 8.1 多路徑映射
    • 8.2 窄化請求路徑
    • 8.3 請求方法限定
  • 9. Controller方法回傳值
    • 9.1 回傳ModelAndView
    • 9.2 回傳void
    • 9.3 回傳字串
      • 9.3.1 邏輯視圖名
      • 9.3.2 Redirect重定向
      • 9.3.3 forward轉發
  • 10. 例外處理器
    • 10.1 例外處理器分析
    • 10.2 自定義例外
    • 10.3 例外處理器撰寫
    • 10.4 例外頁面
    • 10.5 測驗程式
  • 11. 上傳圖片
    • 11.1 單圖片上傳
      • 11.1.1 JSP頁面
      • 11.1.2 檔案上傳決議器
      • 11.1.3 Controller實作
    • 11.2 多圖片上傳
      • 11.2.1 JSP頁面
      • 11.2.2 JavaBean
      • 11.2.3 Controller實作
  • 12. JSON資料互動
    • 12.1 概述
    • 12.2 前端發送ajax請求,后端獲取json資料
    • 12.3 后端給前端回應Json資料.
  • 13. RESTful支持
    • 13.1 什么是RESTful
    • 13.2 添加jar包
    • 13.3 修改web.xml,支持RESTful
    • 13.4 JSP頁面
    • 13.5 Controller實作
    • 13.6 靜態資源問題及解決
  • 14. 攔截器
    • 14.1 概述
    • 14.2 分析
    • 14.3 自定義 攔截器
      • 14.3.1 JSP頁面,測驗入口
      • 14.3.2 控制器,測驗程式
      • 14.3.3 攔截器實作類
      • 14.3.4 注冊攔截器
      • 14.3.5 執行結果
    • 14.4 多攔截器配置
      • 14.4.1 分析
      • 14.4.2 攔截器實作類
      • 14.4.3 注冊 攔截器
      • 14.4.4 執行結果
  • 15. 附錄
    • 15.1 SpringMVC01_pom
  • 后記

前言

上回分別為各位分享了《六萬字最全總結Java資料庫編程MyBatis》《爆肝萬字!一文最全總結之Spring從入門到入土》,
沒有學過的同學,建議先學MyBatis,后學Spring,這次在此基礎上我們來學習SpringMVC,此篇學完再無后端!

??爆肝六萬字最全總結Java資料庫編程MyBatis(建議收藏)

??爆肝萬字!一文最全總結之Spring從入門到入土??(建議收藏)

相關資料:

已上傳到Gitee,歡迎start!!

在這里插入圖片描述

1. Spring MVC 概述

2.1 Spring MVC是什么

? Spring web mvc是表現層的框架,它是Spring框架的一部分,我們可以從Spring的整體結構中看得出來:

img

1.0 Spring MVC處理流程

img

l 1)核心控制器:處理特定請求,(例如:以*.action為后綴)

名稱:DispatcherServlet

配置:是一個servlet,需要在web.xml中配置,

XML:需要確定核心XML組態檔的位置

l 2)核心XML組態檔:確定Controller位置、確定JSP頁面位置

名稱:springmvc.xml

l 3)控制器:開發人員撰寫的主要內容

名稱:*Controller

l 流程示意圖

img

2. 入門案例:查詢詳情 ( xml)

3.1 需求說明

在index.html中點擊 Hello SpringMVC 超鏈接,在 show01 .jsp 頁面顯示資訊,

2.1 思路分析

整體思路:

跟HelloServlet入門案例幾乎相同 .

服務器設定一個Controller,相當于之前的Servlet,可以接收請求,把請求在轉發給jsp頁面.

這里的區別就是需要設定web.xml和springmvc.xml兩個組態檔,前者是用來配置核心控制器,后者是用來掃描我們自己書寫的Controller的.

img

書寫步驟:

1.拷貝pom檔案,SpringMVC.xml檔案和web.xml組態檔核心代碼.

2.創建HelloController和show01.jsp

專案結構如下:

img

2.2 實作步驟

2.2.1 拷貝組態檔相關代碼

獲取pom檔案:

參見當前檔案末尾的附錄 <SpringMVC01_pom>

獲取springmvc.xml檔案

代碼如下直接拷貝

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:p="http://www.springframework.org/schema/p"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
                  http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
                  http://www.springframework.org/schema/mvc
                  http://www.springframework.org/schema/mvc/spring-mvc-4.2.xsd
                  http://www.springframework.org/schema/context
                  http://www.springframework.org/schema/context/spring-context-4.2.xsd">
    <!-- 掃描注解包 -->
    <context:component-scan base-package="com.Maynor.controller" />  
</beans>

獲取Web.xml代碼配置如下:

<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_4_0.xsd"
         version="4.0">

  <display-name>Archetype Created Web Application</display-name>


  <!-- 設定核心配置器 -->  
  <servlet>
    <servlet-name>springmvc</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>
  </servlet>
  <servlet-mapping>
    <servlet-name>springmvc</servlet-name>
    <url-pattern>*.action</url-pattern>  
  </servlet-mapping>

</web-app>

2.2.2 創建java類和jsp檔案

創建HelloController.java 
package com.Maynor.controller;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller  
public class HelloController {

   @RequestMapping("/hello.action")  
   public String show(Model model){

      model.addAttribute("data", "嘿嘿嘿"); 

      return "/WEB-INF/show01.jsp"; 
   }

}

Show01.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>

你好啊 老弟兒 ${data}

</body>
</html>

Index.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<body>
<h2>Hello World!</h2>

<a href="${pageContext.request.contextPath}/hello.action">入門案例</a>
</body>
</html>

測驗結果:
index.jsp頁面

img

點擊入門案例結果:

img

3. 入門查詢:查詢所有(無xml)

3.2 需求說明

該需求跟上一個入門案例需求完全相同.

在index.html中點擊 Hello SpringMVC 超鏈接,在 show01 .jsp 頁面顯示資訊,

區別在于實作的時候:

使用 WebInitializer類代替web.xml

使用MVCConfig代替springmvc.xml

3.1 思路分析

img

書寫步驟:

1.拷貝pom檔案,書寫MVCConfig和WebInitializer類.

2.創建HelloController和show01.jsp

專案結構如下:

img

3.2 步驟實作

3.2.1 拷貝pom檔案,創建MVCConfig和WebInitializer類

Pom檔案,沿用上一個案例.即附錄 <SpringMVC01_pom>

MVCConfig類代碼如下:

package com.Maynor.config;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScan("com.Maynor.controller")  
public class MVCConfig {
}

傳統Web專案中,程式的入口是web.xml檔案,

? 在spring4中提供WebApplicationInitializer介面,表示服務器啟動初始化,也就是說介面實作類中撰寫的內容,就是web.xml檔案中配置的內容,

類或方法描述
AnnotationConfigWebApplicationContextWEB環境下spring工廠
servletContext.addFilter(name , Class)添加過濾器,等效
servletContext.addServlet(name , Class)添加servlet,等效
過濾器相關方法 ServletRegistration.Dynamic描述
addMapping(urlPatterns)追加過濾路徑
setLoadOnStartup(int)設定啟動順序

WebInitializer類代碼如下:

package com.Maynor.config;

import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.web.WebApplicationInitializer;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.servlet.DispatcherServlet;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRegistration;

public class WebInitializer implements WebApplicationInitializer {
   @Override
   public void onStartup(ServletContext servletContext) throws ServletException {

      //1.初始化spring容器
      AnnotationConfigWebApplicationContext applicationContext = new AnnotationConfigWebApplicationContext();
      applicationContext.register(MVCConfig.class);  
      applicationContext.setServletContext(servletContext);
      //2.設定核心控制器
      ServletRegistration.Dynamic springMVCServlet = servletContext.addServlet("springmvc", new DispatcherServlet(applicationContext)); 
      springMVCServlet.addMapping("*.action"); 
      springMVCServlet.setLoadOnStartup(2);

   }
}

3.2.2 創建HelloController和show01.jsp

HelloController代碼:
package com.Maynor.controller;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class HelloController {

   @RequestMapping(path = "/hello.action")
   public String show(Model model){

      model.addAttribute("data", "呵呵呵");
      
      return "/WEB-INF/show01.jsp";

   }


}
Show01.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>

    來了 老弟兒 ${data}

</body>
</html>

測驗結果:
img

練習:

查詢所有. 希望得到如下結果:

img

參考代碼:

img

l 撰寫JavaBean用于封裝資料

public class Item {
	private String name;	//名稱
	private Float price;	//價格
	private String detail;	//詳情

l 撰寫業務控制器Controller

@Controller
@RequestMapping("/user")
public class HelloController {

    @RequestMapping("showInfo")
    public String showInfo(Model model){
        System.out.println("展示頁面");
        //1 模擬資料
        List<Item> list = new ArrayList<Item>();
        list.add(new Item("聯想筆記本", 6999f, "ThinkPad T430 聯想筆記本電腦!"));
        list.add(new Item("蘋果手機", 8800f, "iphone X 蘋果手機!"));

        //設定資料
        model.addAttribute("list", list);
        return "/showInfo.jsp";
    }
}

l 展示資料

? img

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%--
  Created by IntelliJ IDEA.
  User: 86153
  Date: 2019/6/14
  Time: 0:50
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
<table border="1">
    <tr>
        <td>名稱</td>
        <td>價格</td>
        <td>描述</td>
    </tr>
    <c:forEach items="${list}" var="item">
        <tr>
            <td>${item.name }</td>
            <td>${item.price }</td>
            <td>${item.detail }</td>
        </tr>
    </c:forEach>
</table>
</body>
</html>

配置類

img

*MVCConfig
@Configuration
@ComponentScan("com.Maynor.controller")
public class MVCConfiguration {

}


WebInitalizer
public class WebInitializer implements WebApplicationInitializer {

	@Override
	public void onStartup(ServletContext servletContext) throws ServletException {
		//1 初始化spring容器
		AnnotationConfigWebApplicationContext appliation = new AnnotationConfigWebApplicationContext();
		appliation.register(MVCConfiguration.class);
		appliation.setServletContext(servletContext);
		
		//3 前端控制器
		ServletRegistration.Dynamic springMvcServlet = servletContext.addServlet("springmvc", new DispatcherServlet(appliation));  
		springMvcServlet.addMapping("*.action");
		springMvcServlet.setLoadOnStartup(2);

	}

}

測驗:

l 步驟2:啟動,并訪問

http://localhost:8080/s02/user/showInfo.action

img

4. SSM整合:改造UMS

需求:

改造ums 實作 查詢所有用戶.

示意圖如下:

img

思路:

  1. 環境搭建:拷貝pom,資源檔案和組態檔,初始化資料庫和表,創建javaBean

  2. 撰寫功能:dao,Service,Controller

  3. 撰寫配置類:SpringConfig,MyBatisConfig,SpringMvcConfig,Web啟動類.

  4. 測驗

專案最終結構如下:

img

4.1 搭建環境

4.0.1 創建專案、 拷貝pom檔案

<org.springframework.version>4.2.4.RELEASE</org.springframework.version>

<dependencies>
  <!-- spring start -->

  <!--spring core start-->
  <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-beans</artifactId>
    <version>${org.springframework.version}</version>
  </dependency>
  <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-core</artifactId>
    <version>${org.springframework.version}</version>
  </dependency>
  <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>${org.springframework.version}</version>
  </dependency>
  <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-expression</artifactId>
    <version>${org.springframework.version}</version>
  </dependency>
  <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context-support</artifactId>
    <version>${org.springframework.version}</version>
  </dependency>
  <!--spring core end-->

  <!--spring aop start-->
  <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aop</artifactId>
    <version>${org.springframework.version}</version>
  </dependency>
  <!--spirng aop end-->

  <!--spring aspects start-->
  <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aspects</artifactId>
    <version>${org.springframework.version}</version>
  </dependency>
  <!--spring aspects end-->

  <!--spring instrumentation start -->
  <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-instrument</artifactId>
    <version>${org.springframework.version}</version>
  </dependency>
  <!--spring instrumentation end-->

  <!--spring messaging start -->
  <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-messaging</artifactId>
    <version>${org.springframework.version}</version>
  </dependency>
  <!--spring messaging end-->

  <!--spring data access start -->
  <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-jdbc</artifactId>
    <version>${org.springframework.version}</version>
  </dependency>
  <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-orm</artifactId>
    <version>${org.springframework.version}</version>
  </dependency>
  <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-oxm</artifactId>
    <version>${org.springframework.version}</version>
  </dependency>
  <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-jms</artifactId>
    <version>${org.springframework.version}</version>
  </dependency>
  <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-tx</artifactId>
    <version>${org.springframework.version}</version>
  </dependency>
  <!--spring data access end-->

  <!--spring web start -->
  <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-websocket</artifactId>
    <version>${org.springframework.version}</version>
  </dependency>
  <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-web</artifactId>
    <version>${org.springframework.version}</version>
  </dependency>


  <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webmvc-portlet</artifactId>
    <version>${org.springframework.version}</version>
  </dependency>

  <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webmvc</artifactId>
    <version>${org.springframework.version}</version>
  </dependency>
  <!--spring web end -->

  <!--spring test start -->
  <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-test</artifactId>
    <version>${org.springframework.version}</version>
  </dependency>

  <!--spring test end -->
  <!-- spring end -->


  <dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.12</version>
    <scope>test</scope>
  </dependency>
  <dependency>
    <groupId>tk.mybatis</groupId>
    <artifactId>mapper</artifactId>
    <version>3.5.2</version>
  </dependency>
  <dependency>
    <groupId>com.github.pagehelper</groupId>
    <artifactId>pagehelper</artifactId>
    <version>3.7.5</version>
  </dependency>
  <dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis</artifactId>
    <version>3.4.5</version>
  </dependency>

  <dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.47</version>
  </dependency>
  <dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis-spring</artifactId>
    <version>1.3.2</version>
  </dependency>
  <dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid</artifactId>
    <version>1.1.10</version>
  </dependency>

  <dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>javax.servlet-api</artifactId>
    <version>3.1.0</version>
    <scope>provided</scope>
  </dependency>


  <dependency>
    <groupId>jstl</groupId>
    <artifactId>jstl</artifactId>
    <version>1.2</version>
  </dependency>


  <dependency>
    <groupId>javax.servlet.jsp</groupId>
    <artifactId>jsp-api</artifactId>
    <version>2.1</version>
    <scope>provided</scope>
  </dependency>
  
</dependencies>


<!-- jdk版本插件 -->
<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-compiler-plugin</artifactId>
  <version>3.2</version>
  <configuration>
    <source>1.8</source>
    <target>1.8</target>
    <encoding>UTF-8</encoding>
    <showWarnings>true</showWarnings>
  </configuration>
</plugin>

<!-- tomcat7插件 -->
<plugin>
  <groupId>org.apache.tomcat.maven</groupId>
  <artifactId>tomcat7-maven-plugin</artifactId>
  <version>2.1</version>
  <configuration>
    <port>8081</port>
    <server>tomcat7</server>
  </configuration>
</plugin>

4.0.2 拷貝UMS頁面

img

4.0.3 組態檔

jdbc.driver=com.mysql.jdbc.Driver

jdbc.url=jdbc:mysql://127.0.0.1:3306/ums_db

jdbc.username=root

jdbc.password=1234

4.0.4 初始化資料庫和表

CREATE TABLE t_user (

 uid INT(11) PRIMARY KEY NOT NULL AUTO_INCREMENT,

 login_name VARCHAR(50) DEFAULT NULL,

 login_pwd VARCHAR(32) DEFAULT NULL,

 age INT(11) DEFAULT NULL,

 birthday DATE DEFAULT NULL,

 sex VARCHAR(1) DEFAULT NULL,

 education VARCHAR(50),

 telephone VARCHAR(11),

 interest VARCHAR(100),

 remark VARCHAR(200)

)
insert  into `t_user`(`uid`,`login_name`,`login_pwd`,`age`,`birthday`,`sex`,`education`,`telephone`,`interest`,`remark`) values (1,'jack','1234',18,'1996-11-11','男',NULL,NULL,NULL,NULL),(2,'rose','1234',21,'1993-11-11','女',NULL,NULL,NULL,NULL),(3,'tom','1234',23,'1996-12-24','男',NULL,NULL,NULL,NULL);

4.0.5 創建JavaBean

@Table(name="t_user")
public class User {
	@Id
	private Integer uid;
	private String loginName;
	private String loginPwd;
	private Integer age;
	private String sex;
	private String birthday;
	private String education;
	private String telephone;
	private String interest;		//愛好:對應資料庫(內容:A,B,C)
	private String[] interestArr;	//愛好:對應頁面表單
	private String remark;

l 愛好需要特殊處理

?

	public String getInterest() {
		if(interestArr != null){
			interest = Arrays.toString(interestArr);  //[A,B,C]
			interest = interest.substring(1, interest.length() - 1);	//A,B,C
		}
		return interest;
	}
	public void setInterest(String interest) {
		this.interest = interest;
		if(interest != null){
			interestArr = interest.split(", ");
		}
	}

img

4.1 撰寫功能:dao、service、web、jsp頁面

4.1.1 撰寫mapper介面(dao)

package com.Maynor.dao;

import com.Maynor.domain.User;
import tk.mybatis.mapper.common.Mapper;

public interface UserMapper extends Mapper<User> {
}

4.1.2 撰寫service介面

package com.Maynor.service;

import com.Maynor.domain.User;

import java.util.List;

public interface UserService {

   public List<User> findAll();
   
}

4.1.3 撰寫service實作類

package com.Maynor.service.impl;

import com.Maynor.dao.UserMapper;
import com.Maynor.domain.User;
import com.Maynor.service.UserService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import tk.mybatis.mapper.common.Mapper;

import javax.annotation.Resource;
import java.util.List;

@Service(value = "userServiceImpl")
@Transactional
public class UserServiceImpl implements UserService {


   @Resource
   private UserMapper userMapper;

   @Override
   public List<User> findAll() {

      List<User> users = userMapper.selectAll();

      return users;
   }
}

4.1.4 撰寫Controller

package com.Maynor.controller;


import com.Maynor.domain.User;
import com.Maynor.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;

import javax.annotation.Resource;
import java.util.List;

@Controller
public class UserController {

   @Autowired
   private UserService userService;

   @RequestMapping("/findAllUsers.action")
   public String findAll(Model model){

      List<User> userList = userService.findAll();

      model.addAttribute("userList", userList);

      return "/user/list.jsp";
   }


}

4.1.5 撰寫jsp

List.jsp

img

Left.jsp

${pageContext.request.contextPath}/findAllUsers.action

img

4.2 撰寫配置類

img

4.2.1 spring配置類

package com.Maynor.config;

import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.transaction.annotation.TransactionManagementConfigurer;
import org.springframework.web.bind.annotation.RequestMapping;

import javax.annotation.Resource;
import javax.sql.DataSource;

//配置類
@Configuration
//要掃描的包
@ComponentScan(basePackages = {"com.Maynor"})
//開啟事務支持
@EnableTransactionManagement
//讀取properties組態檔
@PropertySource(value = "classpath:db.properties")
public class SpringConfig {

   //4.2.4 讀取properties的固定代碼
   @Bean
   public static PropertySourcesPlaceholderConfigurer create(){

      return new PropertySourcesPlaceholderConfigurer();
   }
   //讀取資料庫中的相關配置
   @Value("${jdbc.driver}")
   private String driverClass;
   @Value("${jdbc.url}")
   private String url;
   @Value("${jdbc.username}")
   private String username;
   @Value("${jdbc.password}")
   private String password;


   //設定德魯伊連接池
   @Bean
   public DataSource dataSource(){
      DruidDataSource dataSource = new DruidDataSource();
      dataSource.setPassword(password);
      dataSource.setUsername(username);
      dataSource.setUrl(url);
      dataSource.setDriverClassName(driverClass);
      return dataSource;
   }
   //開啟事務管理器
   @Bean
   @Resource
   public DataSourceTransactionManager txManager(DataSource dataSource){
      return  new DataSourceTransactionManager(dataSource);
   }
}

4.2.2 mybatis配置類

package com.Maynor.config;

import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.transaction.annotation.TransactionManagementConfigurer;
import org.springframework.web.bind.annotation.RequestMapping;

import javax.annotation.Resource;
import javax.sql.DataSource;

//配置類
@Configuration
//要掃描的包
@ComponentScan(basePackages = {"com.Maynor"})
//開啟事務支持
@EnableTransactionManagement
//讀取properties組態檔
@PropertySource(value = "classpath:db.properties")
public class SpringConfig {

   //4.2.4 讀取properties的固定代碼
   @Bean
   public static PropertySourcesPlaceholderConfigurer create(){

      return new PropertySourcesPlaceholderConfigurer();
   }
   //讀取資料庫中的相關配置
   @Value("${jdbc.driver}")
   private String driverClass;
   @Value("${jdbc.url}")
   private String url;
   @Value("${jdbc.username}")
   private String username;
   @Value("${jdbc.password}")
   private String password;


   //設定德魯伊連接池
   @Bean
   public DataSource dataSource(){
      DruidDataSource dataSource = new DruidDataSource();
      dataSource.setPassword(password);
      dataSource.setUsername(username);
      dataSource.setUrl(url);
      dataSource.setDriverClassName(driverClass);
      return dataSource;
   }
   //開啟事務管理器
   @Bean
   @Resource
   public DataSourceTransactionManager txManager(DataSource dataSource){
      return  new DataSourceTransactionManager(dataSource);
   }
}

4.2.3 spring mvc 配置類【無內容】

package com.Maynor.config;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

//宣告為配置類
@Configuration
//設定掃描 controller
@ComponentScan("com.Maynor.controller")
public class SpringMvcConfig {
}

4.2.4 web啟動配置類【新內容】

? 傳統Web專案中,程式的入口是web.xml檔案,

? 在spring4中提供WebApplicationInitializer介面,表示服務器啟動初始化,也就是說介面實作類中撰寫的內容,就是web.xml檔案中配置的內容,

類或方法描述
AnnotationConfigWebApplicationContextWEB環境下spring工廠
servletContext.addFilter(name , Class)添加過濾器,等效
servletContext.addServlet(name , Class)添加servlet,等效
過濾器相關方法 ServletRegistration.Dynamic描述
addMapping(urlPatterns)追加過濾路徑
setLoadOnStartup(int)設定啟動順序
過濾器相關方法 FilterRegistration.Dynamic描述
addMappingForUrlPatterns(null, isMatchAfter, urlPatterns)追加過濾路徑引數2:引數3:路徑
package com.Maynor.config;


import org.springframework.web.WebApplicationInitializer;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.filter.CharacterEncodingFilter;
import org.springframework.web.servlet.DispatcherServlet;

import javax.servlet.FilterRegistration;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRegistration;

public class WebInitializer implements WebApplicationInitializer {
   @Override
   public void onStartup(ServletContext servletContext) throws ServletException {
      //1.初始化 Spring 容器
      AnnotationConfigWebApplicationContext applicationContext  = new AnnotationConfigWebApplicationContext();
      applicationContext.register(SpringMvcConfig.class);
      applicationContext.register(SpringConfig.class);
      applicationContext.register(MybatisConfig.class);
      applicationContext.setServletContext(servletContext);

      //2.設定核心控制器
      ServletRegistration.Dynamic ds = servletContext.addServlet("springmvc", new DispatcherServlet(applicationContext));
      ds.addMapping("*.action");
      ds.setLoadOnStartup(2);


      //3 post亂碼配置    
      FilterRegistration.Dynamic encodingFilter = servletContext.addFilter("CharacterEncodingFilter", new CharacterEncodingFilter("UTF-8"));
      encodingFilter.addMappingForUrlPatterns(null, true, "/*");

   }
}

4.3 測驗

啟動專案,點擊用戶管理 可以看到如下效果即可.

img

5. 視圖 決議器

5.1 分析

img

5.2 修改代碼

l 其他代碼與“查詢所有”案例相同,不同內容如下:

img

5.2.1 撰寫控制器

l 業務控制器回傳“視圖”名稱

@Controller
@RequestMapping("/user")
public class ItemsController {
	
	@RequestMapping("/itemsList")
	public String itemsList(Model model) throws Exception {
		
		//1 模擬資料
		List<Items> list = new ArrayList<Items>();
		list.add(new Items("聯想筆記本", 6999f, "ThinkPad T430 聯想筆記本電腦!"));
		list.add(new Items("蘋果手機", 8800f, "iphone X 蘋果手機!"));
		
		//設定資料
		model.addAttribute("list", list);
		
		return "itemslist"; //"/WEB-INF/jsp/itemslist.jsp";
	}

}

5.2.2 配置視圖決議器

@Configuration
@ComponentScan("com.Maynor.controller")
public class MVCConfiguration {
	@Bean
	public InternalResourceViewResolver viewResolver(){
		InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
		viewResolver.setPrefix("/WEB-INF/jsp/");
		viewResolver.setSuffix(".jsp");
		return viewResolver;
	}
}

6. SSM整合:改造UMS(添加視圖決議器)

7. 引數 系結

7.1 簡單資料型別

l 在控制器的方法中,只要有對應的引數名,spring mvc就可以自動完成引數封裝,

img

7.1.1 支持的資料型別

l 引數型別推薦使用包裝資料型別,因為基礎資料型別不可以為null,此時進行訪問沒有設定引數,程式拋例外,

資料型別
整型:Integer、int
字串:String
單精度:Float、float
雙精度:Double、double
布爾型:Boolean、boolean

7.1.2 @RequestParam

l 如果請求引數名和方法引數名不一致時,需要使用@RequestParam標記對應關系,

img

l 如果型別是基本型別,此時沒有引數,默認拋例外,

解決方案1:可以設定默認值,

img

解決方案2:可以設定成 包裝型別

7.2 系結POJO型別

?JSP頁面
<form action="${pageContext.request.contextPath}/user/additems.action" method="post">
		姓名:<input type="text" name="name"/> <br/>
		價格:<input type="text" name="price"/> <br/>
		<input type="submit" value="提交" />
	</form>
?控制器:
@Controller
@RequestMapping("/user")
public class ItemsController {

	@RequestMapping("additems")
	public String addItems(Items items){
		System.out.println(items);
		return "itemslist";
	}
}

l 分析

img

l 注意:資料不能是日期,日期必須采用自定義引數系結,

7.3 POST中文亂碼

?在web.xml檔案中
<filter>
    <filter-name>encodingFilter</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>forceEncoding</param-name>
        <param-value>true</param-value>
    </init-param>
</filter>
<filter-mapping>
    <filter-name>encodingFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>
?我們采用web啟動配置類的方式
	@Override
	public void onStartup(ServletContext servletContext) throws ServletException {
		//1 初始化spring容器
		AnnotationConfigWebApplicationContext appliation = new AnnotationConfigWebApplicationContext();
		appliation.register(MVCConfiguration.class);
		appliation.setServletContext(servletContext);
		
		//2 post亂碼配置 
		FilterRegistration.Dynamic encodingFilter = servletContext.addFilter("CharacterEncodingFilter", new CharacterEncodingFilter("UTF-8"));
		encodingFilter.addMappingForUrlPatterns(null, true, "/*");
		
		//3 前端控制器
		ServletRegistration.Dynamic springMvcServlet = servletContext.addServlet("springmvc", new DispatcherServlet(appliation));  
		springMvcServlet.addMapping("*.action");
		springMvcServlet.setLoadOnStartup(2);

	}

7.4 系結包裝POJO

?提供JavaBean:QueryVo
public class QueryVo {
	private Items items;

	public Items getItems() {
		return items;
	}

	public void setItems(Items items) {
		this.items = items;
	}
}
?修改控制器
	@RequestMapping("findall")
	public String findAll(QueryVo queryVo){
		System.out.println(queryVo.getItems());
		return "itemslist";
	}
?JSP頁面
<form action="${pageContext.request.contextPath}/user/findall.action" method="post">
		姓名:<input type="text" name="items.name"/> <br/>
		價格:<input type="text" name="items.price"/> <br/>
		<input type="submit" value="提交findall" />
	</form>

7.5 自定義引數系結

? 由于日期資料有很多種格式,所以springmvc沒辦法把字串轉換成日期型別(不夠智能,2019/01/01這種格式可以自動轉,2019-01-01這種格式就不能了),所以需要自定義引數系結,

?JavaBean
public class QueryVo {
	private Items items;
	private Date createDate;
?JSP頁面
<form action="${pageContext.request.contextPath}/user/findall2.action" method="post">
		姓名:<input type="text" name="items.name"/> <br/>
		價格:<input type="text" name="items.price"/> <br/>
		日期:<input type="text" name="createDate"/> <br/>
		<input type="submit" value="提交findall2" />
	</form>
?控制器
	@RequestMapping("findall2")
	public String findAll2(QueryVo queryVo){
		System.out.println(queryVo.getItems());
		System.out.println(queryVo.getCreateDate());
		return "itemslist";
	}

方式一:

\1. 在MVCConfig類上添加@EnableWebMvc 注解

\2. 在物體類上添加注解@DateTimeFormat

?JavaBean
public class QueryVo {
	private Items items;
	private Date createDate;
?JSP頁面
<form action="${pageContext.request.contextPath}/user/findall2.action" method="post">
		姓名:<input type="text" name="items.name"/> <br/>
		價格:<input type="text" name="items.price"/> <br/>
		日期:<input type="text" name="createDate"/> <br/>
		<input type="submit" value="提交findall2" />
	</form>
?控制器
	@RequestMapping("findall2")
	public String findAll2(QueryVo queryVo){
		System.out.println(queryVo.getItems());
		System.out.println(queryVo.getCreateDate());
		return "itemslist";
	}

7.6 系結陣列

?JavaBean
public class QueryVo {
	private Items items;
	private Date createDate;
?JSP頁面
<form action="${pageContext.request.contextPath}/user/findall2.action" method="post">
		姓名:<input type="text" name="items.name"/> <br/>
		價格:<input type="text" name="items.price"/> <br/>
		日期:<input type="text" name="createDate"/> <br/>
		<input type="submit" value="提交findall2" />
	</form>
?控制器
	@RequestMapping("findall2")
	public String findAll2(QueryVo queryVo){
		System.out.println(queryVo.getItems());
		System.out.println(queryVo.getCreateDate());
		return "itemslist";
	}

7.7 表單資料系結到List

?

?JavaBean
public class QueryVo {
	private Items items;
	private Date createDate;
?JSP頁面
<form action="${pageContext.request.contextPath}/user/findall2.action" method="post">
		姓名:<input type="text" name="items.name"/> <br/>
		價格:<input type="text" name="items.price"/> <br/>
		日期:<input type="text" name="createDate"/> <br/>
		<input type="submit" value="提交findall2" />
	</form>
?控制器
	@RequestMapping("findall2")
	public String findAll2(QueryVo queryVo){
		System.out.println(queryVo.getItems());
		System.out.println(queryVo.getCreateDate());
		return "itemslist";
	}

8. @RequestMapping

8.1 多路徑映射

l 同時設定多個路徑

@RequestMapping(value={"/index","/index2"})
	public String index(){
		return "itemslist";
	}

http://localhost:8080/spring_mvc_day01_05/user/index.action
http://localhost:8080/spring_mvc_day01_05/user/index2.action
//都可以訪問 

8.2 窄化請求路徑

@RequestMapping放在類名上邊,設定請求前綴

@RequestMapping放在方法名上邊,設定方法對應請求路徑,

完整請求:前綴 + 請求路徑

img

8.3 請求方法限定

l 限定GET方法

@RequestMapping(method = RequestMethod.GET)

l 限定POST方法

@RequestMapping(method = RequestMethod.POST)

l GET和POST都可以

@RequestMapping(method={RequestMethod.GET,RequestMethod.POST})

9. Controller方法回傳值

9.1 回傳ModelAndView

controller方法中定義ModelAndView物件并回傳,物件中可添加model資料、指定view,

?

@RequestMapping("/findById")
	public ModelAndView findById(){
		ModelAndView modelAndview = new ModelAndView();
		//設定資料
		modelAndview.addObject("id", "猜猜看");
		//設定視圖
		modelAndview.setViewName("itemslist");
		return modelAndview;
	}

9.2 回傳void

如果方法回傳void,有3種情況:request請求轉發、response重定向、給前端回應Json

?請求轉發
@RequestMapping("/findById2")
public void findById2(HttpServletRequest request , HttpServletResponse response) 
								throws ServletException, IOException{
	request.getRequestDispatcher("/index.jsp").forward(request, response);
}
?重定向
@RequestMapping("/findById3")
public void findById3(HttpServletRequest request , HttpServletResponse response) 
								throws ServletException, IOException{
	response.sendRedirect(request.getContextPath() + "/index.jsp");
}
?Json 處理
@RequestMapping("/findById4")
public void findById4(HttpServletRequest request , HttpServletResponse response)
								 throws ServletException, IOException{
	response.setCharacterEncoding("UTF-8");
	response.setContentType("application/json;charset=UTF-8");
	String jsonStr = "{\"username\":\"jack\"}";
	response.getWriter().write(jsonStr);
}

9.3 回傳字串

9.3.1 邏輯視圖名

controller方法回傳字串可以指定邏輯視圖名,通過視圖決議器決議為物理視圖地址,

@RequestMapping(value={"/index","/index2"})
public String index(){
	return "itemslist";
}

9.3.2 Redirect重定向

? Contrller方法回傳結果重定向到一個url地址,如下商品修改提交后重定向到商品查詢方法,引數無法帶到商品查詢方法中,

return "redirect:其他路徑";

@RequestMapping("/update")
public String update() throws ServletException, IOException{
	return "redirect:queryItem.action";
}

9.3.3 forward轉發

? controller方法執行后繼續執行另一個controller方法,如下商品修改提交后轉向到商品修改頁面,修改商品的id引數可以帶到商品修改方法中,

return "forward:其他路徑";
@RequestMapping("/updateSubmit")
public String updateSubmit() throws ServletException, IOException{
	return "forward:editItem.action";
}

10. 例外處理器

10.1 例外處理器分析

img

10.2 自定義例外

img

public class CustomException extends Exception {

	private static final long serialVersionUID = 8222256702797084775L;

	public CustomException() {
		super();
	}

	public CustomException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
		super(message, cause, enableSuppression, writableStackTrace);
	}

	public CustomException(String message, Throwable cause) {
		super(message, cause);
	}

	public CustomException(String message) {
		super(message);
	}

	public CustomException(Throwable cause) {
		super(cause);
	}
	
}

10.3 例外處理器撰寫

public class CustomException extends Exception {

	private static final long serialVersionUID = 8222256702797084775L;

	public CustomException() {
		super();
	}

	public CustomException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
		super(message, cause, enableSuppression, writableStackTrace);
	}

	public CustomException(String message, Throwable cause) {
		super(message, cause);
	}

	public CustomException(String message) {
		super(message);
	}

	public CustomException(Throwable cause) {
		super(cause);
	}
	
}

10.4 例外頁面

<body>
	您的操作出現錯誤如下:<br/>
	${message }
</body>

img

10.5 測驗程式

@Controller
@RequestMapping("/user")
public class ItemsController {
	
	@RequestMapping("index")
	public String index(String id) throws CustomException{
		if(id == null){
			throw new CustomException("沒有id引數");
		}
		return "itemslist";
	}
}

<a href="${pageContext.request.contextPath}/user/index.action">例外演示</a><br/>

例外演示

11. 上傳圖片

11.1 單圖片上傳

11.1.1 JSP頁面

<form id="itemForm" action="${pageContext.request.contextPath }/user/upload.action" method="post" enctype="multipart/form-data">
		姓名:<input type="text" name="name"/> <br/>
		價格:<input type="text" name="price"/> <br/>
		圖片:<input type="file" name="picFile"/> <br/>
		<input type="submit" value="提交" />
	</form>

11.1.2 檔案上傳決議器

<form id="itemForm" action="${pageContext.request.contextPath }/user/upload.action" method="post" enctype="multipart/form-data">
		姓名:<input type="text" name="name"/> <br/>
		價格:<input type="text" name="price"/> <br/>
		圖片:<input type="file" name="picFile"/> <br/>
		<input type="submit" value="提交" />
	</form>

l 使用的commons-fileupload完成上傳,確定匯入fileupload jar包

? img

<dependency>
  <groupId>commons-fileupload</groupId>
  <artifactId>commons-fileupload</artifactId>
  <version>1.2.2</version>
</dependency>

<dependency>
  <groupId>commons-io</groupId>
  <artifactId>commons-io</artifactId>
  <version>2.3</version>
</dependency>

11.1.3 Controller實作

需要使用MultipartFile型別表示一個檔案上傳物件,

方法名描述
String getOriginalFilename()獲得原始上傳檔案名
transferTo(File file)將上傳檔案轉換到一個指定的檔案中
String getContentType()獲取檔案MIME型別,如image/pjpeg、text/plain等
String getName()獲取表單中檔案組件的名字

?

	@RequestMapping("upload")
	public String upload(String name,Double price,
@RequestParam(required=false,value="picFile") MultipartFile picFile) throws Exception{
		System.out.println("姓名:" + name);
		System.out.println("價格:" + price);
		
		String originalFileName = picFile.getOriginalFilename();
		System.out.println("上傳檔案名:" + originalFileName);
		//保存檔案到指定的位置
		File file = new File("D:\\temp", originalFileName);
		picFile.transferTo(file);
		return "itemslist";
	}

11.2 多圖片上傳

11.2.1 JSP頁面

<form id="itemForm" action="${pageContext.request.contextPath }/user/upload2.action"
 								method="post" enctype="multipart/form-data">
		姓名:<input type="text" name="name"/> <br/>
		價格:<input type="text" name="price"/> <br/>
		圖片:<input type="file" name="picFile"/> <br/>
		圖片:<input type="file" name="picFile"/> <br/>
		<input type="submit" value="提交" />
	</form>

11.2.2 JavaBean

public class QueryVo {
	private String name;
	private Double price;
	public List<MultipartFile> picFile;

	//getter and setter

11.2.3 Controller實作

?

@RequestMapping("upload2")
	public String upload2(QueryVo queryVo) throws Exception{
		System.out.println("姓名:" + queryVo.getName());
		System.out.println("價格:" + queryVo.getPrice());
		
		System.out.println("上傳檔案個數:" + queryVo.getPicFile().size());
		for(MultipartFile picFile : queryVo.getPicFile()){
			String originalFileName = picFile.getOriginalFilename();
			System.out.println("上傳檔案名:" + originalFileName);
			//保存檔案到指定的位置
			File file = new File("D:\\temp", originalFileName);
			picFile.transferTo(file);
		}
		return "itemslist";
	}

12. JSON資料互動

12.1 概述

@RequestBody:將json、xml 等內容 轉換 成Java物件,

@ResponseBody:將Java物件 轉換 成 json、xml等內容,

12.2 前端發送ajax請求,后端獲取json資料

需求:

前端發送ajax請求,后端通過VO自動獲取資料列印


  前端代碼:
   <%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>

    <script src="${pageContext.request.contextPath}/js/jquery-3.3.1.js"></script>
    <script>
        $(function () {

            var url = "${pageContext.request.contextPath}/tJson.action";
            var params={
                "name":"zhangsan",
                "price":"123"
            }
            var callBack=function (rel) {
                //后端有回傳結果 就會彈窗顯示, 沒有就不會彈窗
                alert(rel.name+" "+rel.price)
            }
            //發射
            $.post(url,params,callBack,"json")

        })
    </script>
</head>
<body>
  頁面加載完畢就發射ajax 
</body>
</html>
后端代碼: 
 Qvo 
  public class QVo {

    private String name;
    private Double price;
....
}

Controller
@RequestMapping("/tJson.action")
public String testJson(QVo qvo){
    //查看前端傳遞的json 自動轉化的VO結果
    System.out.println(qvo);

    return "/show04.jsp";//隨便轉發到一個頁面,不影響測驗結果.
}

測驗結果:

img

12.3 后端給前端回應Json資料.

需求:

跟上一個例子類似, 前端發送請求給后端, 后端接收資料后給前端再相應回一個json資料.

該例子中,需要直接把java物件通過SpringMvc自動轉化成json資料. 需要使用兩個東西完成.

\1. 匯入Jackson-databind坐標

\2. 在方法的回傳值上使用@ResponseBody注解.

具體代碼如下:

Pom檔案坐標
<dependency>
  <groupId>com.fasterxml.jackson.core</groupId>
  <artifactId>jackson-databind</artifactId>
  <version>2.9.7</version>
</dependency>

Controller代碼:
@RequestMapping("tj.action")
public @ResponseBody QVo getInfo(String name,Double price){

    System.out.println("接收到前端資料:"+name+" "+price);

    //創建一個物件, 通過SpringMvc自動把這個物件轉化成Json回應給前端
    QVo qVo = new QVo("lisiguang", 220.4);
    return qVo;
}

前端:
<script src="${pageContext.request.contextPath}/js/jquery-3.3.1.js"></script>
<script>
    $(function () {

        var url = "${pageContext.request.contextPath}/tj.action";
        var params={
            "name":"zhangsan",
            "price":"123"
        }
        var callBack=function (rel) {
            //后端有回傳結果 就會彈窗顯示, 沒有就不會彈窗
            alert(rel.name+" "+rel.price)
        }
        //發射
        $.post(url,params,callBack,"json")

    })
</script>

測驗結果:

后端:

img

前端:

img

13. RESTful支持

13.1 什么是RESTful

? Restful就是一個資源定位及資源操作的風格,不是標準也不是協議,只是一種風格,是對http協議的詮釋,

l 資源定位:每一個URL都是一個資源,要求url中沒有動詞,只有名詞,沒有引數

Url格式:http://blog.csdn.net/beat_the_world/article/details/45621673

l 資源操作:通過HTTP請求方式確定不同的操作,

get查詢資源、post新建資源(也可以修改資源)、put更新資源、delete洗掉資源,

一般使用時還是post和get,

@RequestMapping(value="/viewItems/{id}" , method= RequestMethod.GET )

l RESTful初體驗

在URL中包含操作的資料,而不是通過引數進行傳遞,

13.2 添加jar包

img

13.3 修改web.xml,支持RESTful

	<!-- 前端控制器 -->
  <servlet>
  	<servlet-name>springmvc</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>
  </servlet>
  <servlet-mapping>
  	<servlet-name>springmvc</servlet-name>
  	<url-pattern>/</url-pattern>
  </servlet-mapping>

13.4 JSP頁面

<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
	<script type="text/javascript" src="${pageContext.request.contextPath}/js/jquery-1.12.4.js"></script>
	<script type="text/javascript">
		$(function(){
			alert("靜態資源(js)可以使用");
		});
	</script>
</head>
<body>
	<a href="${pageContext.request.contextPath}/user/viewItems/1">查詢id=1</a><br/>
	<a href="${pageContext.request.contextPath}/user/viewItems/999.action">查詢id=999</a><br/>
	
</body>

13.5 Controller實作

?通過@RequestMapping可以設定URL模板模式映射,
?@RequestMapping(value="/ viewItems/{xxx}") ,{xxx}相當于占位符,可以匹配到/viewItems/1、/viewItems/2 等路徑
?xxx就是占位符的名稱,用于方法引數獲得匹配到的資料
?通過@PathVariable(“xxx”) 獲得從路徑匹配到的對應資料


	@RequestMapping("/viewItems/{id}")
	public String viewItems(@PathVariable("id") String id , Model model) {
		model.addAttribute("id", id);
		return "itemslist";
	}

13.6 靜態資源問題及解決

l 當程式運行時,首頁的js代碼將不能執行,

原因:DispatcherServlet中設定url-pattern為 /,靜態資源不能成功訪問,

解決:配置 mvc:resources

<!-- 確保所有注解正常使用 -->
<mvc:annotation-driven></mvc:annotation-driven>
	
<!-- 靜態資源訪問 -->
<mvc:resources location="/js/" mapping="/js/*"></mvc:resources>

14. 攔截器

14.1 概述

? Spring Web MVC 的處理器攔截器類似于Servlet 開發中的過濾器Filter,用于對處理器執行前后進行處理,

? 自定義連接性需要實作介面:HandlerInterceptor

14.2 分析

img

方法名描述
boolean preHandle()在處理器(控制器)前執行,回傳一個boolean值,true:繼續執行處理器,false:程式直接結束,
void postHandle()在處理器方法執行后,視圖顯示前執行,
void afterCompletion()在視圖決議成功后執行,

14.3 自定義 攔截器

14.3.1 JSP頁面,測驗入口

<a href="${pageContext.request.contextPath}/user/index.action">攔截器演示</a><br/>

14.3.2 控制器,測驗程式

@Controller
@RequestMapping("/user")
public class ItemsController {
	
	@RequestMapping("index")
	public String index(String id) {
		System.out.println("2.controller");
		return "itemslist";
	}
}

14.3.3 攔截器實作類

img

package com.Maynor.interceptor;

import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@Component
public class MyInterceptor1 implements HandlerInterceptor {
    /*
     * 在方法執行之前執行
     * 如果回傳true 繼續執行下一個攔截器
     * 如果回傳false,請求被終止
     * @param request
     * @param response
     * @param handler
     * @return
     * @throws Exception
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("MyInterceptor1攔截器的preHandle");
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("MyInterceptor1攔截器的postHandle");
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("MyInterceptor1攔截器的afterCompletion");
    }
}

14.3.4 注冊攔截器

攔截器撰寫完成之后,需要在SpringMVCConfiguration組態檔中注冊

注冊步驟:

1 SpringMVCConfiguration實作WebMvcConfigurerAdapter

2 重寫AddInterceptors方法

public class SpringMvcConfig  extends WebMvcConfigurerAdapter {
    @Autowired
    private MyInterceptor1 myInterceptor1;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        InterceptorRegistration interceptorRegistration1 = registry.addInterceptor(myInterceptor1);
        interceptorRegistration1.addPathPatterns("/*");
    }
     //.....
}

14.3.5 執行結果

img

14.4 多攔截器配置

14.4.1 分析

img

14.4.2 攔截器實作類

img

package com.Maynor.interceptor;

import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@Component
public class MyInterceptor2 implements HandlerInterceptor {
    /*
     * 在方法執行之前執行
     * 如果回傳true 繼續執行下一個攔截器
     * 如果回傳false,則程式終止
     * @param request
     * @param response
     * @param handler
     * @return
     * @throws Exception
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("MyInterceptor2攔截器的preHandle");
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("MyInterceptor2攔截器的postHandle");
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("MyInterceptor2攔截器的afterCompletion");
    }
}

14.4.3 注冊 攔截器

@Resource
private MyInterceptor1 myInterceptor1;

@Resource
private MyInterceptor2 myInterceptor2;

@Override
public void addInterceptors(InterceptorRegistry registry) {

    //攔截全部
    InterceptorRegistration interceptorRegistration2 = registry.addInterceptor(myInterceptor2);
    interceptorRegistration2.addPathPatterns("/*");
    //攔截全部
    InterceptorRegistration interceptorRegistration = registry.addInterceptor(myInterceptor1);
    interceptorRegistration.addPathPatterns("/*");

}

14.4.4 執行結果

img

15. 附錄

用到的相關組態檔

15.1 SpringMVC01_pom

SpringMVC入門案例1的pom檔案核心代碼

Pom.xml檔案

<properties>
  <org.springframework.version>4.2.4.RELEASE</org.springframework.version>
</properties>


<dependencies>
    <!-- spring start -->

    <!--spring core start-->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-beans</artifactId>
        <version>${org.springframework.version}</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-core</artifactId>
        <version>${org.springframework.version}</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>${org.springframework.version}</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-expression</artifactId>
        <version>${org.springframework.version}</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context-support</artifactId>
        <version>${org.springframework.version}</version>
    </dependency>
    <!--spring core end-->

    <!--spring aop start-->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-aop</artifactId>
        <version>${org.springframework.version}</version>
    </dependency>
    <!--spirng aop end-->

    <!--spring aspects start-->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-aspects</artifactId>
        <version>${org.springframework.version}</version>
    </dependency>
    <!--spring aspects end-->

    <!--spring instrumentation start -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-instrument</artifactId>
        <version>${org.springframework.version}</version>
    </dependency>
    <!--spring instrumentation end-->

    <!--spring messaging start -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-messaging</artifactId>
        <version>${org.springframework.version}</version>
    </dependency>
    <!--spring messaging end-->

    <!--spring data access start -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-jdbc</artifactId>
        <version>${org.springframework.version}</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-orm</artifactId>
        <version>${org.springframework.version}</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-oxm</artifactId>
        <version>${org.springframework.version}</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-jms</artifactId>
        <version>${org.springframework.version}</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-tx</artifactId>
        <version>${org.springframework.version}</version>
    </dependency>
    <!--spring data access end-->

    <!--spring web start -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-websocket</artifactId>
        <version>${org.springframework.version}</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-web</artifactId>
        <version>${org.springframework.version}</version>
    </dependency>


    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc-portlet</artifactId>
        <version>${org.springframework.version}</version>
    </dependency>

    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc</artifactId>
        <version>${org.springframework.version}</version>
    </dependency>
    <!--spring web end -->

    <!--spring test start -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-test</artifactId>
        <version>${org.springframework.version}</version>
    </dependency>

    <!--spring test end -->
    <!-- spring end -->


    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.12</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>tk.mybatis</groupId>
        <artifactId>mapper</artifactId>
        <version>3.5.2</version>
    </dependency>
    <dependency>
        <groupId>com.github.pagehelper</groupId>
        <artifactId>pagehelper</artifactId>
        <version>3.7.5</version>
    </dependency>
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis</artifactId>
        <version>3.4.5</version>
    </dependency>

    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>5.1.47</version>
    </dependency>
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis-spring</artifactId>
        <version>1.3.2</version>
    </dependency>
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>druid</artifactId>
        <version>1.1.10</version>
    </dependency>

    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>javax.servlet-api</artifactId>
        <version>3.1.0</version>
        <scope>provided</scope>
    </dependency>

    <dependency>
        <groupId>jstl</groupId>
        <artifactId>jstl</artifactId>
        <version>1.2</version>
    </dependency>

</dependencies>

<!-- jdk版本插件 -->
<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-compiler-plugin</artifactId>
  <version>3.2</version>
  <configuration>
    <source>1.8</source>
    <target>1.8</target>
    <encoding>UTF-8</encoding>
    <showWarnings>true</showWarnings>
  </configuration>
</plugin>

<!-- tomcat7插件 -->
<plugin>
  <groupId>org.apache.tomcat.maven</groupId>
  <artifactId>tomcat7-maven-plugin</artifactId>
  <version>2.1</version>
  <configuration>
    <port>8080</port>
    <server>tomcat7</server>
  </configuration>
</plugin>

后記

📢博客主頁:https://manor.blog.csdn.net
📢歡迎點贊 👍 收藏 ?留言 📝 如有錯誤敬請指正!
📢本文由 manor 原創,首發于 CSDN博客🙉
📢不能老盯著手機螢屏,要不時地抬起頭,看看老板的位置?

轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/306417.html

標籤:java

上一篇:《十萬字Java入門練習100例》1-10例——紙上得來終覺淺,絕知此事要躬行

下一篇:第一屆LeetCode刷題打卡贏現金活動開始啦,助力每一位想拿大廠offer的小伙伴!

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 【C++】Microsoft C++、C 和匯編程式檔案

    ......

    uj5u.com 2020-09-10 00:57:23 more
  • 例外宣告

    相比于斷言適用于排除邏輯上不可能存在的狀態,例外通常是用于邏輯上可能發生的錯誤。 例外宣告 Item 1:當函式不可能拋出例外或不能接受拋出例外時,使用noexcept 理由 如果不打算拋出例外的話,程式就會認為無法處理這種錯誤,并且應當盡早終止,如此可以有效地阻止例外的傳播與擴散。 示例 //不可 ......

    uj5u.com 2020-09-10 00:57:27 more
  • Codeforces 1400E Clear the Multiset(貪心 + 分治)

    鏈接:https://codeforces.com/problemset/problem/1400/E 來源:Codeforces 思路:給你一個陣列,現在你可以進行兩種操作,操作1:將一段沒有 0 的區間進行減一的操作,操作2:將 i 位置上的元素歸零。最終問:將這個陣列的全部元素歸零后操作的最少 ......

    uj5u.com 2020-09-10 00:57:30 more
  • UVA11610 【Reverse Prime】

    本人看到此題沒有翻譯,就附帶了一個自己的翻譯版本 思考 這一題,它的第一個要求是找出所有 $7$ 位反向質數及其質因數的個數。 我們應該需要質數篩篩選1~$10^{7}$的所有數,這里就不慢慢介紹了。但是,重讀題,我們突然發現反向質數都是 $7$ 位,而將它反過來后的數字卻是 $6$ 位數,這就說明 ......

    uj5u.com 2020-09-10 00:57:36 more
  • 統計區間素數數量

    1 #pragma GCC optimize(2) 2 #include <bits/stdc++.h> 3 using namespace std; 4 bool isprime[1000000010]; 5 vector<int> prime; 6 inline int getlist(int ......

    uj5u.com 2020-09-10 00:57:47 more
  • C/C++編程筆記:C++中的 const 變數詳解,教你正確認識const用法

    1、C中的const 1、區域const變數存放在堆疊區中,會分配記憶體(也就是說可以通過地址間接修改變數的值)。測驗代碼如下: 運行結果: 2、全域const變數存放在只讀資料段(不能通過地址修改,會發生寫入錯誤), 默認為外部聯編,可以給其他源檔案使用(需要用extern關鍵字修飾) 運行結果: ......

    uj5u.com 2020-09-10 00:58:04 more
  • 【C++犯錯記錄】VS2019 MFC添加資源不懂如何修改資源宏ID

    1. 首先在資源視圖中,添加資源 2. 點擊新添加的資源,復制自動生成的ID 3. 在解決方案資源管理器中找到Resource.h檔案,編輯,使用整個專案搜索和替換的方式快速替換 宏宣告 4. Ctrl+Shift+F 全域搜索,點擊查找全部,然后逐個替換 5. 為什么使用搜索替換而不使用屬性視窗直 ......

    uj5u.com 2020-09-10 00:59:11 more
  • 【C++犯錯記錄】VS2019 MFC不懂的批量添加資源

    1. 打開資源頭檔案Resource.h,在其中預先定義好宏 ID(不清楚其實ID值應該設定多少,可以先新建一個相同的資源項,再在這個資源的ID值的基礎上遞增即可) 2. 在資源視圖中選中專案資源,按F7編輯資源檔案,按 ID 型別 相對路徑的形式添加 資源。(別忘了先把檔案拷貝到專案中的res檔案 ......

    uj5u.com 2020-09-10 01:00:19 more
  • C/C++編程筆記:關于C++的參考型別,專供新手入門使用

    今天要講的是C++中我最喜歡的一個用法——參考,也叫別名。 參考就是給一個變數名取一個變數名,方便我們間接地使用這個變數。我們可以給一個變數創建N個參考,這N + 1個變數共享了同一塊記憶體區域。(參考型別的變數會占用記憶體空間,占用的記憶體空間的大小和指標型別的大小是相同的。雖然參考是一個物件的別名,但 ......

    uj5u.com 2020-09-10 01:00:22 more
  • 【C/C++編程筆記】從頭開始學習C ++:初學者完整指南

    眾所周知,C ++的學習曲線陡峭,但是花時間學習這種語言將為您的職業帶來奇跡,并使您與其他開發人員區分開。您會更輕松地學習新語言,形成真正的解決問題的技能,并在編程的基礎上打下堅實的基礎。 C ++將幫助您養成良好的編程習慣(即清晰一致的編碼風格,在撰寫代碼時注釋代碼,并限制類內部的可見性),并且由 ......

    uj5u.com 2020-09-10 01:00:41 more
最新发布
  • Rust中的智能指標:Box<T> Rc<T> Arc<T> Cell<T> RefCell<T> Weak

    Rust中的智能指標是什么 智能指標(smart pointers)是一類資料結構,是擁有資料所有權和額外功能的指標。是指標的進一步發展 指標(pointer)是一個包含記憶體地址的變數的通用概念。這個地址參考,或 ” 指向”(points at)一些其 他資料 。參考以 & 符號為標志并借用了他們所 ......

    uj5u.com 2023-04-20 07:24:10 more
  • Java的值傳遞和參考傳遞

    值傳遞不會改變本身,參考傳遞(如果傳遞的值需要實體化到堆里)如果發生修改了會改變本身。 1.基本資料型別都是值傳遞 package com.example.basic; public class Test { public static void main(String[] args) { int ......

    uj5u.com 2023-04-20 07:24:04 more
  • [2]SpinalHDL教程——Scala簡單入門

    第一個 Scala 程式 shell里面輸入 $ scala scala> 1 + 1 res0: Int = 2 scala> println("Hello World!") Hello World! 檔案形式 object HelloWorld { /* 這是我的第一個 Scala 程式 * 以 ......

    uj5u.com 2023-04-20 07:23:58 more
  • 理解函式指標和回呼函式

    理解 函式指標 指向函式的指標。比如: 理解函式指標的偽代碼 void (*p)(int type, char *data); // 定義一個函式指標p void func(int type, char *data); // 宣告一個函式func p = func; // 將指標p指向函式func ......

    uj5u.com 2023-04-20 07:23:52 more
  • Django筆記二十五之資料庫函式之日期函式

    本文首發于公眾號:Hunter后端 原文鏈接:Django筆記二十五之資料庫函式之日期函式 日期函式主要介紹兩個大類,Extract() 和 Trunc() Extract() 函式作用是提取日期,比如我們可以提取一個日期欄位的年份,月份,日等資料 Trunc() 的作用則是截取,比如 2022-0 ......

    uj5u.com 2023-04-20 07:23:45 more
  • 一天吃透JVM面試八股文

    什么是JVM? JVM,全稱Java Virtual Machine(Java虛擬機),是通過在實際的計算機上仿真模擬各種計算機功能來實作的。由一套位元組碼指令集、一組暫存器、一個堆疊、一個垃圾回收堆和一個存盤方法域等組成。JVM屏蔽了與作業系統平臺相關的資訊,使得Java程式只需要生成在Java虛擬機 ......

    uj5u.com 2023-04-20 07:23:31 more
  • 使用Java接入小程式訂閱訊息!

    更新完微信服務號的模板訊息之后,我又趕緊把微信小程式的訂閱訊息給實作了!之前我一直以為微信小程式也是要企業才能申請,沒想到小程式個人就能申請。 訊息推送平臺🔥推送下發【郵件】【短信】【微信服務號】【微信小程式】【企業微信】【釘釘】等訊息型別。 https://gitee.com/zhongfuch ......

    uj5u.com 2023-04-20 07:22:59 more
  • java -- 緩沖流、轉換流、序列化流

    緩沖流 緩沖流, 也叫高效流, 按照資料型別分類: 位元組緩沖流:BufferedInputStream,BufferedOutputStream 字符緩沖流:BufferedReader,BufferedWriter 緩沖流的基本原理,是在創建流物件時,會創建一個內置的默認大小的緩沖區陣列,通過緩沖 ......

    uj5u.com 2023-04-20 07:22:49 more
  • Java-SpringBoot-Range請求頭設定實作視頻分段傳輸

    老實說,人太懶了,現在基本都不喜歡寫筆記了,但是網上有關Range請求頭的文章都太水了 下面是抄的一段StackOverflow的代碼...自己大修改過的,寫的注釋挺全的,應該直接看得懂,就不解釋了 寫的不好...只是希望能給視頻網站開發的新手一點點幫助吧. 業務場景:視頻分段傳輸、視頻多段傳輸(理 ......

    uj5u.com 2023-04-20 07:22:42 more
  • Windows 10開發教程_編程入門自學教程_菜鳥教程-免費教程分享

    教程簡介 Windows 10開發入門教程 - 從簡單的步驟了解Windows 10開發,從基本到高級概念,包括簡介,UWP,第一個應用程式,商店,XAML控制元件,資料系結,XAML性能,自適應設計,自適應UI,自適應代碼,檔案管理,SQLite資料庫,應用程式到應用程式通信,應用程式本地化,應用程式 ......

    uj5u.com 2023-04-20 07:22:35 more