java day48——springMVC

chronos+發表於2020-10-15

基本概念

三層架構

MVC模型

SpringMVC

在這裡插入圖片描述

元件

<web-app>
  <display-name>Archetype Created Web Application</display-name>
<!--  亂碼過濾器-->
  <filter>
    <filter-name>CharacterEncodingFilter</filter-name>
    <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
    <init-param>
      <param-name>encoding</param-name>
      <param-value>UTF-8</param-value>
    </init-param>
  </filter>
  <filter-mapping>
    <filter-name>CharacterEncodingFilter</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>

<!-- 配置前端控制器 -->
  <servlet>
    <servlet-name>DispatcherServlet</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <!-- 配置初始化引數: 指定springmvc配置檔案路徑 -->
    <init-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>classpath:springmvc.xml</param-value>
    </init-param>
    <!-- 設定生命週期: 伺服器啟動建立Servlet物件 -->
    <load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
    <servlet-name>DispatcherServlet</servlet-name>
    <!-- /*  攔截所有,包括靜態資源 .PNG .CSS .JS .JSP ...
         /   攔截所有,不包括 .JSP  一般常用於網際網路應用
         *.do     一般在xx管理系統使用
     -->
    <url-pattern>/</url-pattern>
  </servlet-mapping>
    <!-- 配置建立 spring 容器要掃描的包 -->
    <context:component-scan base-package="com.zzxx"/>
<!--    同時註冊處理器介面卡和處理器對映器-->
    <mvc:annotation-driven"/>
    <!-- 配置檢視解析器 -->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/pages/"/>
        <property name="suffix" value=".jsp"/>
    </bean>
@Controller
// 這個類中所有的處理器方法, 都會在路徑上加統一的上級目錄
@RequestMapping(path="/spring")
public class HelloController {
    // <servlet-name>
    // params = "username" : 表示請求中必須包含username引數
    @RequestMapping(value={"/hello", "/hehe"}, method = {RequestMethod.POST, RequestMethod.GET}
    , params = {"username=lisi", "age<100"},
    headers = "user-agent")
    public String hello() {
        System.out.println("hello 控制器方法執行了!");
        return "success";
    }

請求響應流程

在這裡插入圖片描述

獲得請求引數

簡單型別

<!-- 傳送請求, 引數為簡單型別 id=1&username=zhangsan -->
<a href="params/simple?id=1&username=zhangsan">接收簡單型別的引數</a><br>

    @RequestMapping("/simple")
    // id=1&username=zhangsan
    // 將請求引數的key, 作為控制器的方法引數 即可
    public String getSimpleParam(int id, String username) {
        System.out.println("接收簡單引數的控制器方法執行...");
        System.out.println(id + ", " +username);
        return "success";
    }

實體類物件

public class Account {
    private int id;
    private String name;
    private double money;
    private User user;
<!-- 傳送請求, 引數為物件型別[引數可以封裝為一個完整的物件] -->
<form action="params/bean" method="post">
    賬號id: <input type="text" name="id"/> <br>
    賬號姓名: <input type="text" name="name"/> <br>
    賬號金額: <input type="text" name="money"/> <br>
<%-- 想要將以下兩個引數值 封裝到上面 account物件中的user屬性裡 --%>
    使用者id: <input type="text" name="user.id"/> <br>
    使用者姓名: <input type="text" name="user.username"/> <br>
    <input type="submit" value="提交">
</form>
 @RequestMapping("/bean")
    // 表單: id=1&name=zhangsan&money=2000.0
    // 將要封裝的物件作為 控制器的方法引數
    // 注意: 引數名key 和物件的屬性名要一致
    public String getBeanParam(Account account) {
        System.out.println("接收物件型別的引數的控制器方法執行...");
        System.out.println(account);
        return "success";

陣列型別

<form action="params/array" method="post">
    <input type="checkbox" name="ids" value="1"/>
    <input type="checkbox" name="ids" value="2"/>
    <input type="checkbox" name="ids" value="3"/>
    <input type="checkbox" name="ids" value="4"/>
    <input type="checkbox" name="ids" value="5"/><br>
    <input type="submit" value="提交">
</form>
@RequestMapping("/array")
    // 陣列/集合 int[] ids  List<Integer> ids;
    // ids=1&ids=2&ids=3&ids=4
    // request.getParameterValues(ids);
    public String getArrayParam(int[] ids) {
        System.out.println(Arrays.toString(ids));
        return "success";
    }

List集合

<form action="params/list" method="post">
    <input type="checkbox" name="ids" value="1"/>
    <input type="checkbox" name="ids" value="2"/>
    <input type="checkbox" name="ids" value="3"/>
    <input type="checkbox" name="ids" value="4"/>
    <input type="checkbox" name="ids" value="5"/><br>
    <input type="submit" value="提交">
</form>
<form action="params/userList" method="post">
    使用者1id: <input type="text" name="userList[0].id"/> <br>
    使用者1姓名: <input type="text" name="userList[0].username"/> <br>

    使用者2id: <input type="text" name="userList[1].id"/> <br>
    使用者2姓名: <input type="text" name="userList[1].username"/> <br>

    使用者3id: <input type="text" name="userList[2].id"/> <br>
    使用者3姓名: <input type="text" name="userList[2].username"/> <br>
    <input type="submit" value="提交">
</form>
public class QueryVo {
    private List<Integer> ids;
    private List<User> userList;
	@RequestMapping("/list")
    // 集合 List<Integer> ids;
    // ids=1&ids=2&ids=3&ids=4
    // request.getParameterValues(ids);
    public String getListParam(QueryVo qv) {
        System.out.println(qv.getIds());
        return "success";
    }
    
    @RequestMapping("/userList")
    // 集合 List<User> userList
    // key
    public String getUserListParam(QueryVo qv) {
        System.out.println(qv.getUserList());
        return "success";
    }

Map

public class QueryVo {
    private Map<String, User> userMap;
<form action="params/userMap" method="post">
    one使用者 id: <input type="text" name="userMap['one'].id"/> <br>
    one使用者 姓名: <input type="text" name="userMap['one'].username"/> <br>

    two使用者id: <input type="text" name="userMap['two'].id"/> <br>
    two使用者姓名: <input type="text" name="userMap['two'].username"/> <br>
    <input type="submit" value="提交">
</form>
    @RequestMapping("/userMap")
    // {one=User1, two=User2}
    public String getUserMapParam(QueryVo qv) {
        System.out.println(qv.getUserMap());
        return "success";
    }

特殊

Date——需要自定義型別轉換器

 <!-- 註冊 轉換器服務工廠 -->
    <bean id="cs2" class="org.springframework.context.support.ConversionServiceFactoryBean">
        <!-- 注入自定義轉換器物件 -->
        <property name="converters">
            <set>
                <bean class="com.zzxx.converter.StringDateConverter"/>
            </set>
        </property>
    </bean>
<form action="params/date">
    生日: <input type="date" name="birthday"><br>
    <input type="submit" value="提交">
</form>
    @RequestMapping("/date")
    // birthday=2020-10-07
    // String -> Date   Converter
    public String getDateParam(Date birthday) {
        System.out.println(birthday);
        return "success";
    }

想要使用傳統的

@RequestMapping("/servletAPI")
    // 想要使用 HttpServletRequest物件 和 HttpServletResponse物件 HttpSession物件
    public String servletAPI(HttpServletRequest request, HttpServletResponse response, HttpSession session) {
        System.out.println(request);
        System.out.println(response);
        System.out.println(session);
        return "success";
    }

常用註解

PathVariable

restful風格URL——輕量,易於擴充套件
只有一個統一的上級目錄,根據method屬性中不同的提交方式進行區分;提交方式相同,根據引數區分

{id} 就是 url 佔位符

@Controller
@RequestMapping("/path")
public class PathVariableController {
    @RequestMapping(method = RequestMethod.GET)
    public String findAll(){
        System.out.println("findAll 方法執行了");
        return "success";
    }
    @RequestMapping(value = "/{id}",method = RequestMethod.GET)
    public String findById(@PathVariable("id") int id){
        System.out.println("findById 方法執行了");
        System.out.println(id);
        return "success";
    }
}
<a href="path/100">pathVariable 註解</a>
瀏覽器get方式提交:http://localhost:8080/my01_war/path/100

SessionAttribute

@SessionAttributes({“username”, “password”,“age”})

@Controller
@RequestMapping("/session")
@SessionAttributes({"username", "password","age"})
public class SessionAttributeController {
    /**
     * 把資料存⼊ SessionAttribute
     * Model 是 spring 提供的⼀個接⼝,該接⼝有⼀個實現類 ExtendedModelMap
     * 該類繼承了 ModelMap,⽽ ModelMap 就是 LinkedHashMap ⼦類
     */
    @RequestMapping("/add")
    public String testPut(Model model) {
        model.addAttribute("username", "張三");
        model.addAttribute("password", "123456");
        model.addAttribute("age", 31);
        System.out.println("存入了資料");
        return "success";
    }
    @RequestMapping("/get")
    public String testGet(ModelMap model) {
        System.out.println("獲取了資料:" + model.get("username") + ";" +
                model.get("password") + ";" + model.get("age"));
        return "success";
    }
<%@ page contentType="text/html;charset=UTF-8" language="java" isELIgnored="false" %>
<body>
    ${username}${password}${age}
</body>

響應資料

返回值分類

String型別返回值

 // 1.String 型別返回值
    @RequestMapping("/testString")
    // Model 是 spring 提供的⼀個接⼝,該接⼝有⼀個實現類 ExtendedModelMap,該類繼承了 ModelMap,⽽ ModelMap 就是 LinkedHashMap ⼦類
    public String testStringReturn(Model model, ModelMap modelMap) {
        System.out.println("testStringReturn 執行了!");
        // 通常在請求轉發之前, 會傳遞資料, 需要用到request域
        model.addAttribute("msg", "hello");
        modelMap.addAttribute("username", "zhangsan");
        // 等同於 請求轉發, 會使用檢視解析器來解析檢視路徑
        return "success";
    }

void沒有返回值

@RequestMapping("/testVoid")
    public void testVoid(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("testVoid 執行了!");
        // 使用request  response 來頁面跳轉
        // 轉發
//        request.getRequestDispatcher("/WEB-INF/pages/success.jsp").forward(request, response);
        // 重定向
//        response.sendRedirect(request.getContextPath() + "/error.jsp");
        // 直接使用response來寫出頁面
        response.setContentType("text/html;charset=utf-8");
        response.getWriter().write("你好!");

ModelAndView 返回值

@RequestMapping("/testModelAndView")
    public ModelAndView testModelAndView() {
        System.out.println("testModelAndView 執行了!");
        ModelAndView mav = new ModelAndView();
        // 1.給mav 新增資料模型, 等同於model.addAttribute()
        mav.addObject("msg", "modelAndView");
        // 2.設定轉發檢視頁面路徑 -- 會經過檢視解析器的處理
        mav.setViewName("success");
        return mav;

轉發和重定向

總結:只有請求轉發(邏輯檢視名方式)和 ModelAndView會經過檢視解析器
使用關鍵字方式的請求和轉發:

    @RequestMapping("/testStringRedirect")
    public String testStringRedirect() {
        System.out.println("testStringRedirect 執行了!");
        // 重定向, 使用關鍵字 redirect, 不會進入檢視解析器新增字首和字尾
        // response.sendRedirect(request.getContextPaht() + "/error.jsp")
        return "redirect:/error.jsp";
    }
 @RequestMapping("/testStringForward")
    public String testStringForward() {
        System.out.println("testStringForward 執行了!");
        // 轉發, 使用關鍵字 forward, 不會進入檢視解析器新增字首和字尾
        return "forward:/WEB-INF/pages/success.jsp";
    }

@ResponseBody 響應 json 資料

	@RequestMapping("/testJson")
    @ResponseBody // 將返回值轉換成json格式字串寫出
    public User testJson(User user) {
        System.out.println("testJson 執行了!");
        user.setId(10);
        // 將user物件轉換成json寫出給客戶端
        // jackson jsonlib fastjson gson
        return user;
    }
<head>
    <script src="js/jquery-1.11.0.min.js"></script>
    <script>
        $(function() {
            $("#btn1").click(function() {
                $.ajax({
                    url: "user/testJson",
                    data: {id: 1, username:"張三"},
                    success: function(user) {
                        alert(user.id);
                        alert(user.username);
                    },
                    dataType: "json",
                    type: "get",
                    async: true
                });});});
    </script>
</head>
<button id="btn1" >傳送ajax請求</button>

檔案上傳

傳統檔案上傳(無spring)

@RequestMapping("/fileupload")
    public String fileUpload(HttpServletRequest request) throws FileUploadException, IOException {
        // 1.獲得磁碟檔案項工廠
        DiskFileItemFactory factory = new DiskFileItemFactory();
        // 2.獲得檔案上傳的核心類物件
        ServletFileUpload upload = new ServletFileUpload(factory);
        // 3.解析請求, 獲得表單項
        List<FileItem> list = upload.parseRequest(request);
        // 4.判斷表單項是否是檔案
        for (FileItem item : list) {
            if (item.isFormField()) {
                // 普通表單項, 獲得引數操作即可
            } else {
                // 5.檔案項, 上傳檔案
                // a.獲得要上傳的檔名
                String filename = item.getName();
                // a.1 檔名的處理
                String uuid = UUID.randomUUID().toString();
                uuid = uuid.replace("-", "");
                filename = uuid + "_" + filename;
                // b.定義上傳檔案的伺服器目標目錄
                String path = request.getServletContext().getRealPath("/uploads");

                // c.上傳
                InputStream in = item.getInputStream();
                OutputStream out = new FileOutputStream(path + "/" + filename);
                int len = 0;
                byte[] buffer = new byte[1024];
                while ((len = in.read(buffer)) > 0) {
                    out.write(buffer, 0, len);
                }
                in.close();
                out.close();
            }
        }
        return "success";
    }

SprignMVC傳統檔案上傳

上傳的⽂件和訪問的應⽤存在於同⼀臺伺服器上

<dependency>
      <groupId>com.sun.jersey</groupId>
      <artifactId>jersey-client</artifactId>
      <version>1.19</version>
    </dependency>
//解除/方式對檔案的過濾
	<mvc:resources mapping="/js/**" location="/js/"/>
    <mvc:resources mapping="/css/**" location="/css/"/>
    <mvc:resources mapping="/images/**" location="/images/"/>
    
<!-- 配置檔案解析器, id固定 multipartResolver -->
    <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
        <!-- 設定上傳檔案的最大上限 -->
        <property name="maxUploadSize" value="5242880"/>
    </bean>
	@RequestMapping("/fileupload2")
    public String fileUpload2(MultipartFile upload, HttpServletRequest request) throws FileUploadException, IOException {
        System.out.println("fileUpload2 的檔案上傳");
        // 5.檔案項, 上傳檔案
        // a.獲得要上傳的檔名
        String filename = upload.getOriginalFilename();
        // a.1 檔名的處理
        String uuid = UUID.randomUUID().toString();
        uuid = uuid.replace("-", "");
        filename = uuid + "_" + filename;
        // b.定義上傳檔案的伺服器目標目錄
        String path = request.getServletContext().getRealPath("/uploads/");
        // c.檔案複製
        upload.transferTo(new File(path, filename));
        return "success";
    }
<FORM action="fileupload2" method="post" enctype="multipart/form-data" >
    使用者名稱:<input type="text" name="username"/><br>
    選擇檔案: <input type="file" name="upload"/><br>
    <input type="submit" value="提交"/>
</FORM>

跨伺服器上傳

兩個tomcat伺服器, tomcat 配置⽂件 webx.xml 中加入允許讀寫操作。
在這裡插入圖片描述

<dependency>
 <groupId>commons-fileupload</groupId>
 <artifactId>commons-fileupload</artifactId>
 <version>1.4</version>
</dependency>
<!-- 此jar包是sun公司提供的 -->
<dependency>
 <groupId>com.sun.jersey</groupId>
 <artifactId>jersey-client</artifactId>
 <version>1.19</version>
</dependency>
/**
     * 跨伺服器上傳檔案
     * 異常: 403程式碼, 檔案伺服器沒有寫入許可權
     *      400程式碼, URI/URL不支援中文 URIEncoder
     * @param upload
     * @return
     */
    @RequestMapping("/fileupload3")
    public String fileUpload3(MultipartFile upload) throws FileUploadException, IOException {
        String file_server = "http://localhost:9090/springmvc02_fileserver_war/uploads/";
        System.out.println("fileUpload3 的檔案上傳");
        // 5.檔案項, 上傳檔案
        // a.獲得要上傳的檔名
        String filename = upload.getOriginalFilename();
        // a.1 檔名的處理
        String uuid = UUID.randomUUID().toString();
        uuid = uuid.replace("-", "");
        filename = uuid + "_" + filename;
        // filename如果是中文, 要處理過, 編碼一下
        filename = URLEncoder.encode(filename, "UTF-8");
        // b.建立一個跨服務的Client物件
        Client client = Client.create();
        // c.獲得上傳檔案的資源物件
        WebResource resource = client.resource(file_server + filename);
        // d.檔案上傳
        resource.put(upload.getBytes());
        return "success";
    }

另一個project的webapp下準備uploads資料夾,其他全空

相關文章