Spring MVC 框架入門學(xué)習(xí)

1.Spring web mvc介紹

Spring web mvc和Struts2都屬于表現(xiàn)層的框架,它是Spring框架的一部分,我們可以從Spring的整體結(jié)構(gòu)中看得出來(lái):

2.Web mvc

  1. 用戶發(fā)起request請(qǐng)求至控制器(Controller)
    控制接收用戶請(qǐng)求的數(shù)據(jù),委托給模型進(jìn)行處理

  2. 控制器通過(guò)模型(Model)處理數(shù)據(jù)并得到處理結(jié)果
    模型通常是指業(yè)務(wù)邏輯

  3. 控制器將模型數(shù)據(jù)在視圖(View)中展示
    web中模型無(wú)法將數(shù)據(jù)直接在視圖上顯示,需要通過(guò)控制器完成。如果在C/S應(yīng)用中模型是可以將數(shù)據(jù)在視圖中展示的脓斩。

  4. 控制器將視圖response響應(yīng)給用戶
    通過(guò)視圖展示給用戶要的數(shù)據(jù)或處理結(jié)果耗拓。

3.Spring web mvc 架構(gòu)

架構(gòu)圖

流程

  1. 用戶發(fā)送請(qǐng)求至前端控制器DispatcherServlet.
  2. DispatcherServlet收到請(qǐng)求調(diào)用HandlerMapping處理器映射器.
  3. 處理器映射器找到具體的處理器揣苏,生成處理器對(duì)象及處理器攔截器(如果有則生成)一并返回給DispatcherServlet.
  4. DispatcherServlet調(diào)用HandlerAdapter處理器適配器.
  5. HandlerAdapter經(jīng)過(guò)適配調(diào)用具體的處理器(Controller涮因,也叫后端控制器).
  6. Controller執(zhí)行完成返回ModelAndView.
  7. HandlerAdaptercontroller執(zhí)行結(jié)果ModelAndView返回給DispatcherServlet.
  8. DispatcherServletModelAndView傳給ViewReslover視圖解析器.
  9. ViewReslover解析后返回具體View.
  10. DispatcherServlet根據(jù)View進(jìn)行渲染視圖(即將模型數(shù)據(jù)填充至視圖中)。
  11. DispatcherServlet響應(yīng)用戶

組件說(shuō)明:

++以下組件通常使用框架提供實(shí)現(xiàn):++

DispatcherServlet:作為前端控制器施符,整個(gè)流程控制的中心,控制其它組件執(zhí)行擂找,統(tǒng)一調(diào)度戳吝,降低組件之間的耦合性,提高每個(gè)組件的擴(kuò)展性贯涎。

HandlerMapping:通過(guò)擴(kuò)展處理器映射器實(shí)現(xiàn)不同的映射方式听哭,例如:配置文件方式,實(shí)現(xiàn)接口方式塘雳,注解方式等陆盘。

HandlAdapter:通過(guò)擴(kuò)展處理器適配器,支持更多類型的處理器粉捻。

ViewResolver:通過(guò)擴(kuò)展視圖解析器礁遣,支持更多類型的視圖解析,例如:jsp肩刃、freemarker祟霍、pdf、excel等盈包。

++下邊兩個(gè)組件通常情況下需要開(kāi)發(fā)++:

Handler:處理器沸呐,即后端控制器用controller表示。

View:視圖呢燥,即展示給用戶的界面崭添,視圖中通常需要標(biāo)簽語(yǔ)言展示模型數(shù)據(jù)。

4.開(kāi)發(fā)環(huán)境準(zhǔn)備

本教程使用Eclipse+tomcat7開(kāi)發(fā)

詳細(xì)參考“Eclipse開(kāi)發(fā)環(huán)境配置-indigo.docx”文檔

5.第一個(gè)springmvc工程

第一步:建立一個(gè)Web項(xiàng)目

在eclipse下創(chuàng)建動(dòng)態(tài)web工程springmvc_01叛氨。

第二步:導(dǎo)入spring3.1.4的jar包

第三步:前端控制器配置

在WEB-INF\web.xml中配置前端控制器呼渣,

<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-servlet.xml</param-value>
    </init-param>
    // 表示servlet隨服務(wù)啟動(dòng)
    <load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
    <servlet-name>springmvc</servlet-name>
    // 以.action結(jié)尾的請(qǐng)求交給DispatcherServlet處理
    <url-pattern>*.action</url-pattern>
</servlet-mapping>

load-on-startup:表示servlet隨服務(wù)啟動(dòng);

url-pattern:*.action的請(qǐng)交給DispatcherServlet處理寞埠。

contextConfigLocation:指定springmvc配置的加載位置屁置,如果不指定則默認(rèn)加載WEB-INF/[DispatcherServlet 的Servlet 名字]-servlet.xml。

第四步:springmvc配置文件

Springmvc默認(rèn)加載WEB-INF/[前端控制器的名字]-servlet.xml仁连,也可以在前端控制器定義處指定加載的配置文件蓝角,如下:

<init-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath:springmvc-servlet.xml</param-value>
</init-param>

如上代碼,通過(guò)contextConfigLocation加載classpath下的springmvc-servlet.xml配置文件,配置文件名稱可以不限定[前端控制器的名字]-servlet.xml使鹅。

第五步:配置處理器映射器

在springmvc-servlet.xml文件配置如下:

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

    <!-- 處理器映射器 -->
    <!-- 根據(jù)bean的name進(jìn)行查找Handler 將action的url配置在bean的name中 -->
    <bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping" />

BeanNameUrlHandlerMapping:表示將定義的Bean名字作為請(qǐng)求的url揪阶,需要將編寫的controller在spring容器中進(jìn)行配置,且指定bean的name為請(qǐng)求的url患朱,且必須以.action結(jié)尾鲁僚。

第六步:配置處理器適配器

在springmvc-servlet.xml文件配置如下:

<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/>

SimpleControllerHandlerAdapter:即簡(jiǎn)單控制器處理適配器,所有實(shí)現(xiàn)了org.springframework.web.servlet.mvc.Controller 接口的Bean作為Springmvc的后端控制器麦乞。

第七步:配置視圖解析器

在springmvc-servlet.xml文件配置如下:

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

InternalResourceViewResolver:支持JSP視圖解析.

viewClass:JstlView表示JSP模板頁(yè)面需要使用JSTL標(biāo)簽庫(kù)蕴茴,所以classpath必須包含jstl的相關(guān)jar包;

prefixsuffix:查找視圖頁(yè)面的前綴和后綴姐直,最終視圖的址為:前綴+邏輯視圖名+后綴倦淀,邏輯視圖名需要在controller中返回ModelAndView指定,比如邏輯視圖名為hello声畏,則最終返回的jsp視圖地址“WEB-INF/jsp/hello.jsp”

第八步:后端控制器開(kāi)發(fā)

后端控制器即controller撞叽,也有稱為action

importjavax.servlet.http.HttpServletRequest;
importjavax.servlet.http.HttpServletResponse;
importorg.springframework.web.servlet.ModelAndView;
importorg.springframework.web.servlet.mvc.Controller;

public class HelloWorldController implements Controller {
    @Override
    Public ModelAndView handleRequest(HttpServletRequest req, HttpServletResponse resp) throws Exception {
        ModelAndView mv = new ModelAndView();
        // 添加模型數(shù)據(jù)
        mv.addObject("message", "Hello World!");
        // 設(shè)置邏輯視圖名,最終視圖地址=前綴+邏輯視圖名+后綴
        mv.setViewName("hello");
        return mv;
      }
}

org.springframework.web.servlet.mvc.Controller:處理器必須實(shí)現(xiàn)Controller 接口插龄。

ModelAndView:包含了模型數(shù)據(jù)及邏輯視圖名

第九步:后端控制器配置

在springmvc-servlet.xml文件配置如下:

<bean name="/hello.action" class="springmvc.action.HelloWorldController"/>

name="/hello.action" :前邊配置的BeanNameUrlHandlerMapping愿棋,表示如過(guò)請(qǐng)求的URL為“上下文/hello.action”,則將會(huì)交給該Bean進(jìn)行處理均牢。

第十步:視圖開(kāi)發(fā)

創(chuàng)建/WEB-INF/jsp/hello.jsp視圖頁(yè)面:

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>第一個(gè)程序</title>
    </head>
    <body>
        <!-- 顯示一行信息hello world!!!! -->
        ${message}
    </body>
</html>

${message}:表示顯示由HelloWorldController處理器傳過(guò)來(lái)的模型數(shù)據(jù)糠雨。

第十一步:部署在tomcat測(cè)試

通過(guò)請(qǐng)求:http://localhost:8080/springmvc_01/hello.action,如果頁(yè)面輸出“Hello World! ”就表明我們成功了徘跪。

總結(jié):

主要進(jìn)行如下操作:

  1. 前端控制器DispatcherServlet配置
    加載springmvc的配置文件
  2. HandlerMapping配置
  3. HandlerAdapter配置
  4. ViewResolver配置
    前綴和后綴
  5. 后端控制器編寫
  6. 后端控制器配置
  7. 視圖編寫

從上邊的步驟可以看出甘邀,通常情況下我們只需要編寫后端控制器和視圖。

6.HandlerMapping處理器映射器

HandlerMapping 給前端控制器返回一個(gè)HandlerExecutionChain 對(duì)象(包含一個(gè)Handler (后端控制器)對(duì)象垮庐、多個(gè)HandlerInterceptor 攔截器)對(duì)象松邪。

BeanNameUrlHandlerMapping

beanName Url映射器

<!—beanName Url映射器 -->
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>

將后端控制器的bean name作為請(qǐng)求的url。

SimpleUrlHandlerMapping

<!—簡(jiǎn)單url映射 -->
    <bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
        <property name="mappings">
            <props>
                <prop key="/hello1.action">hello_controller</prop>
                <prop key="/hello2.action">hello_controller</prop>
            </props>
        </property>
    </bean>

可定義多個(gè)url映射至一個(gè)后端控制器哨查,hello_controller為后端控制器bean的id逗抑。

7.HandlerAdapter處理器適配器

HandlerAdapter會(huì)把后端控制器包裝為一個(gè)適配器,支持多種類型的控制器開(kāi)發(fā)寒亥,這里使用了適配器設(shè)計(jì)模式邮府。

SimpleControllerHandlerAdapter

簡(jiǎn)單控制器處理器適配器.

所有實(shí)現(xiàn)了org.springframework.web.servlet.mvc.Controller接口的Bean作為Springmvc的后端控制器。

適配器配置如下:

<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter" />

HttpRequestHandlerAdapter

HTTP請(qǐng)求處理器適配器.

HTTP請(qǐng)求處理器適配器將http請(qǐng)求封裝成HttpServletResquestHttpServletResponse對(duì)象溉奕,和servlet接口類似褂傀。

適配器配置如下:

<bean class="org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter"/>

Controller實(shí)現(xiàn)如下:

publicclass HelloWorldController2 implements HttpRequestHandler {

    @Override
    publicvoid handleRequest(HttpServletRequest request,HttpServletResponse response) throws ServletException, IOException {
        request.setAttribute("message", "HelloWorld!");
        request.getRequestDispatcher("/WEB-INF/jsp/hello.jsp").forward(request, response);
            // 也可以自定義響應(yīng)內(nèi)容
            //response.setCharacterEncoding("utf-8");
            //response.getWriter().write("HelloWorld!");
    }
}

從上邊可以看出此適配器器的controller方法沒(méi)有返回ModelAndView,可通過(guò)response修改定義響應(yīng)內(nèi)容腐宋。

8.Controller控制器

AbstractCommandController(命令控制器)

該控制器能把請(qǐng)求參數(shù)封裝到一個(gè)命令對(duì)象(模型對(duì)象)中。

public class MyCommandController extends AbstractCommandController {

    /**
     * 通過(guò)構(gòu)造函數(shù)設(shè)置命令對(duì)象
     */
    public MyCommandController(){
        this.setCommandClass(Student.class);
        this.setCommandName("student");//不是必須設(shè)置
    }
    
    @Override
    protected ModelAndView handle(HttpServletRequest request,
            HttpServletResponse response, Object command, BindException errors)
            throws Exception {

        Student student = (Student)command;
        System.out.println(student);
        Return null;
    }

    /**
     * 字符串轉(zhuǎn)換為日期屬性編輯器
     */
    @Override
    Protected void initBinder(HttpServletRequest request,
            ServletRequestDataBinder binder) throws Exception {
        binder.registerCustomEditor(Date.class, new CustomDateEditor(new SimpleDateFormat("yyyy-MM-dd"),true));
    }

}
publicclass Student {
    
    public Student() {
    }
    public Student(String name) {
        this.name = name;
    }
    private String name;//姓名
    private Integer age;//年齡
    private Date birthday;//生日
    private String address;//地址

….get/set方法省略

Controller配置;

<bean id="command_controller" name="/command.action" class="springmvc.action.MyCommandController"/>

使用命令控制器完成查詢列表及表單提交

代碼略

9.問(wèn)題解決

日期格式化

在controller注冊(cè)屬性編輯器

/**
     * 注冊(cè)屬性編輯器(字符串轉(zhuǎn)換為日期)
     */
    @InitBinder
    public void initBinder(HttpServletRequest request,ServletRequestDataBinder binder) throws Exception {
        binder.registerCustomEditor(Date.class, new CustomDateEditor(new SimpleDateFormat("yyyy-MM-dd"),true));
    }

Post時(shí)中文亂碼

web.xml中加入:

<filter>
    <filter-name>CharacterEncodingFilter</filter-name>
    <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
    <init-param>
        <param-name>encoding</param-name>
        <param-value>utf-8</param-value>
    </init-param>
</filter>
<filter-mapping>
    <filter-name>CharacterEncodingFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

以上可以解決post請(qǐng)求亂碼問(wèn)題。

對(duì)于get請(qǐng)求中文參數(shù)出現(xiàn)亂碼解決方法有兩個(gè)

修改tomcat配置文件添加編碼與工程編碼一致胸竞,如下:

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

另外一種方法對(duì)參數(shù)進(jìn)行重新編碼:

String userName new String(request.getParamter("userName").getBytes("ISO8859-1"),"utf-8")

ISO8859-1是tomcat默認(rèn)編碼欺嗤,需要將tomcat編碼后的內(nèi)容按utf-8編碼

10.注解開(kāi)發(fā)

第一個(gè)例子

創(chuàng)建工程的步驟同第一個(gè)springmvc工程,注解開(kāi)發(fā)需要修改handlermapperhandlMapperAdapter卫枝,如下:

springmvc-servlet.xml中配置:

<!--注解映射器 -->   
    <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"/>
    <!--注解適配器 -->
    <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"/>

注解映射器和注解適配器可以使用 <mvc:annotation-driven /> 代替煎饼。
<mvc:annotation-driven /> 默認(rèn)注冊(cè)了注解映射器和注解適配器等bean。

HelloWorldController編寫:

@Controller
publicclass HelloWorldController {

    @RequestMapping(value="/hello")
    public String hello(Model model)throws Exception{
        model.addAttribute("message", "HelloWorld!");
        return"hello";
    }
}

注解描述

@Controller:用于標(biāo)識(shí)是處理器類

@RequestMapping:請(qǐng)求到處理器功能方法的映射規(guī)則

Controller配置

在springmvc-servlet.xml中配置定義的controller:

<!-- controller -->
<bean class="springmvc.action.HelloWorldController"/>

組件掃描

<context:component-scan base-package="springmvc.action" />

掃描 @component 校赤、@controller吆玖、@service@repository 的注解

注意:如果使用組件掃描則controller不需要在springmvc-servlet.xml中配置

11.與struts2不同

  1. springmvc的入口是一個(gè)servlet即前端控制器马篮,而struts2入口是一個(gè)filter過(guò)慮器沾乘。
  2. springmvc是基于方法開(kāi)發(fā),請(qǐng)求參數(shù)傳遞到方法的形參浑测,可以設(shè)計(jì)為單例或多例(建議單例)翅阵,struts2是基于類開(kāi)發(fā),傳遞參數(shù)是通過(guò)類的屬性迁央,只能設(shè)計(jì)為多例掷匠。
  3. Struts采用值棧存儲(chǔ)請(qǐng)求和響應(yīng)的數(shù)據(jù),通過(guò)OGNL存取數(shù)據(jù)岖圈, springmvc通過(guò)參數(shù)解析器是將request請(qǐng)求內(nèi)容解析讹语,并給方法形參賦值,將數(shù)據(jù)和視圖封裝成ModelAndView對(duì)象蜂科,最后又將ModelAndView中的模型數(shù)據(jù)通過(guò)reques域傳輸?shù)巾?yè)面顽决。Jsp視圖解析器默認(rèn)使用jstl。

注意:

不要在action類中定義方法所用到的變量崇摄,變量要定義到方法體中擎值。因?yàn)榉椒ㄊ窃跅?nèi)存中,不會(huì)導(dǎo)致線程問(wèn)題逐抑。

12.@Controller

標(biāo)識(shí)該類為控制器類鸠儿,@controller@service厕氨、@repository 分別對(duì)應(yīng)了web應(yīng)用三層架構(gòu)的組件即控制器进每、服務(wù)接口、數(shù)據(jù)訪問(wèn)接口命斧。

13.@RequestMapping

URL路徑映射

@RequestMapping(value="/user")或@RequestMapping("/user")

根路徑+子路徑

根路徑:

@RequestMapping 放在類名上邊田晚,如下:

@Controller
@RequestMapping("/user")

子路徑:

@RequestMapping 放在方法名上邊,如下:

@RequestMapping("/useradd")
public String useradd(….

URI 模板模式映射

@RequestMapping(value="/useredit/{userId}"):{×××}占位符国葬,請(qǐng)求的URL可以是“/useredit/001”或“/useredit/abc”贤徒,通過(guò)在方法中使用@PathVariable 獲取{×××}中的×××變量芹壕。

@RequestMapping("/useredit/{userid}")
    public String useredit(@PathVariable String userid,Model model) throws Exception{
        //方法中使用@PathVariable獲取useried的值,使用model傳回頁(yè)面
        model.addAttribute("userid", userid);
        return"/user/useredit";
    }

實(shí)現(xiàn)restFul,所有的url都是一個(gè)資源的鏈接接奈,有利于搜索引擎對(duì)網(wǎng)址收錄踢涌。

多個(gè)占位符:

@RequestMapping("/useredit/{groupid}/{userid}")
public String useredit(@PathVariable String groupid,@PathVariable String userid,Model model) throws Exception{
        //方法中使用@PathVariable獲取useried的值,使用model傳回頁(yè)面
        model.addAttribute("groupid", groupid);
        model.addAttribute("userid", userid);
        return"/user/useredit";
    }

頁(yè)面

<td>
    <a href="${pageContext.request.contextPath}/user/editStudent/${student.id}/${student.groupId}/${student.sex}.action">修改</a>
</td>

請(qǐng)求方法限定

限定GET方法

@RequestMapping(method = RequestMethod.GET)

如果通過(guò)Post訪問(wèn)則報(bào)錯(cuò):

HTTP Status 405 - Request method 'POST' not supported

例如

@RequestMapping(value="/useredit/{userid}",method=RequestMethod.GET)

限定POST方法

@RequestMapping(method = RequestMethod.POST)

如果通過(guò)Post訪問(wèn)則報(bào)錯(cuò):

HTTP Status 405 - Request method 'GET' not supported

GET和POST都可以

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

14.請(qǐng)求數(shù)據(jù)綁定(重點(diǎn))

Controller方法通過(guò)形參接收頁(yè)面?zhèn)鬟f的參數(shù)序宦。

如下:

@RequestMapping("/userlist")
public String userlist(
HttpServletRequest request,
            HttpServletResponse response,
            HttpSession session,
            Model model
)

默認(rèn)支持的參數(shù)類型

HttpServletRequest

通過(guò)request對(duì)象獲取請(qǐng)求信息

HttpServletResponse

通過(guò)response處理響應(yīng)信息

HttpSession

通過(guò)session對(duì)象得到session中存放的對(duì)象

session.setAttribute("userinfo", student);
session.invalidate(); // 使session失效

Model

通過(guò)model向頁(yè)面?zhèn)鬟f數(shù)據(jù)睁壁,如下:

model.addAttribute("user", new User("李四"));

頁(yè)面通過(guò)${user.XXXX}獲取user對(duì)象的屬性值。

命令/表單對(duì)象

自動(dòng)將請(qǐng)求參數(shù)綁定到功能處理方法的命令/表單對(duì)象上互捌。

Controller方法通過(guò)形參接收命令/表單對(duì)象潘明。

Java基本數(shù)據(jù)類型

布爾型:

頁(yè)面如下:

<tr>
    <td>用戶狀態(tài):</td>
    <td>
        <inputtype="radio"name="userstate"value="true"/>
        <inputtype="radio"name="userstate"value="false"/>
    </td>
</tr>

整型
例子略

單精度/雙精度
例子略

日期型需要添加屬性編輯器:

@InitBinder
    Public void initBinder(HttpServletRequest request,ServletRequestDataBinder binder) throws Exception {
        binder.registerCustomEditor(Date.class, new CustomDateEditor(new SimpleDateFormat("yyyy-MM-dd"),true));

例子略

Pojo對(duì)象

頁(yè)面上以pojo對(duì)象中屬性名稱命名:

將pojo對(duì)象中的屬性名于傳遞進(jìn)來(lái)的屬性名對(duì)應(yīng),如果傳進(jìn)來(lái)的參數(shù)名稱和對(duì)象中的屬性名稱一致則將參數(shù)值設(shè)置在pojo對(duì)象中

頁(yè)面定義如下;

<input type="text" name="age"/>
<input type="text" name="birthday"/>

Contrller方法定義如下:

public String useraddsubmit(Model model,User user)throws Exception{
    System.out.println(user);
}

頁(yè)面上以pojo對(duì)象名點(diǎn)屬性名命名:

如果采用類似struts中對(duì)象.屬性的方式命名秕噪,需要將pojo對(duì)象作為一個(gè)包裝對(duì)象的屬性钳降,action中以該包裝對(duì)象作為形參。

包裝對(duì)象定義如下:

Public class UserVo {
    private User user;
    
    public User getUser() {
        return user;
    }
    
    Public void setUser(User user) {
        this.user = user;
    }
}

頁(yè)面定義:

<input type="text" name="user.age" />
<input type="text" name="user.birthday" />

Controller方法定義如下:

public String useraddsubmit(Model model,UserVo userVo)throws Exception{
    System.out.println(userVo.getUser());
}

字符串?dāng)?shù)組

使用情景:頁(yè)面提交批量數(shù)據(jù)以數(shù)組接受

頁(yè)面定義如下:

頁(yè)面選中多個(gè)checkbox向controller方法傳遞

<c:forEach items="${studentList}" var="student">
    <tr>
        <td><input type="checkbox" name="deleteids" value="${student.id }"></td>
        <td>${student.id}</td>
        <td>${student.name}</td>

傳遞到controller方法中的格式是:001,002,003

Controller方法中可以用String[]接收巢价,定義如下:

@RequestMapping("/deleteStudent")
    public String deleteStudent(String[] deleteids)throws Exception {
        return "editStudentSubmit";
    }

List

List中存放對(duì)象牲阁,并將定義的List放在包裝類中,action使用包裝對(duì)象接收壤躲。

List中對(duì)象:

成績(jī)對(duì)象

public class StudentScore {
    private String coursename;//課程名稱
    private Float score;//成績(jī)
    public String getCoursename() {
        returncoursename;
    }
    Public void setCoursename(String coursename) {
        this.coursename = coursename;
    }
    public Float getScore() {
        returnscore;
    }
    Public void setScore(Float score) {
        this.score = score;
    }
}

Public class UserVo {
Private List<StudentScore> scores;//成績(jī)

  //get/set方法..
}

包裝類中定義List對(duì)象城菊,并添加get/set方法如下:

private List<StudentScore> scores;//成績(jī)

頁(yè)面:

<tr>
    <td>課程成績(jī):</td>
    <td>
        課程名:<input type="text"name="scores[0].coursename"/>成績(jī):<input type="text"name="scores[0].score"/><br/>
        課程名:<input type="text"name="scores[1].coursename"/>成績(jī):<input type="text"name="scores[1].score"/><br/>
        課程名:<input type="text"name="scores[2].coursename"/>成績(jī):<input type="text"name="scores[2].score"/><br/>
    </td>
</tr>

Contrller方法定義如下:

public String useraddsubmit(Model model,UserVo userVo)throws Exception{
System.out.println(userVo.getScores ());
}

Map

在包裝類中定義Map對(duì)象,并添加get/set方法碉克,action使用包裝對(duì)象接收凌唬。

包裝類中定義Map對(duì)象如下:

Public class UserVo {
    private Map<String, Object>studentinfo = new HashMap<String, Object>();
  //get/set方法..
}

頁(yè)面定義如下:

<tr>
    <td>學(xué)生信息:</td>
    <td>
    姓名:<inputtype="text"name="studentinfo['name']"/>
    年齡:<inputtype="text"name="studentinfo['age']"/>
.. .. ..

<!-- studentinfo是包裝對(duì)象中的屬性名

[]里邊name是存儲(chǔ)map中的key

action中將map定義在包裝對(duì)象中,以包裝對(duì)象接收數(shù)據(jù)漏麦。--!>

    </td>
</tr>

Contrller方法定義如下:

public String useraddsubmit(Model model,UserVo userVo)throws Exception{
    System.out.println(userVo.getStudentinfo());
}

注意:包含日期的要進(jìn)行格式轉(zhuǎn)換(放到action中

// 使用注解進(jìn)行日期格式數(shù)據(jù)轉(zhuǎn)換
    @InitBinder
    private void initBinder(HttpServletRequest request, ServletRequestDataBinder binder) throws Exception {
        // 指定日期類型及日期數(shù)據(jù)的格式
        // 日期類型要和student類的birthday一致
        binder.registerCustomEditor(Date.class, new CustomDateEditor(new SimpleDateFormat("yyyy-MM-dd"), true));
    }

@RequestParam綁定單個(gè)請(qǐng)求參數(shù)

value:參數(shù)名字客税,即入?yún)⒌恼?qǐng)求參數(shù)名字,如value=“studentid”表示請(qǐng)求的參數(shù)區(qū)中的名字為studentid的參數(shù)的值將傳入撕贞;

required:是否必須更耻,默認(rèn)是true,表示請(qǐng)求中一定要有相應(yīng)的參數(shù)捏膨,否則將報(bào)400錯(cuò)誤碼秧均;
defaultValue:默認(rèn)值,表示如果請(qǐng)求中沒(méi)有同名參數(shù)時(shí)的默認(rèn)值

定義如下:

public String userlist(@RequestParam(defaultValue="2",value="group",required=true) String groupid) {

}

形參名稱為groupid号涯,但是這里使用value="group"限定參數(shù)名為group目胡,所以頁(yè)面?zhèn)鬟f參數(shù)的名必須為group

這里通過(guò)required=true限定groupid參數(shù)為必需傳遞链快,如果不傳遞則報(bào)400錯(cuò)誤誉己,由于使用了defaultvalue=”2”默認(rèn)值即使不傳group參數(shù)它的值為”2”,所以頁(yè)面不傳遞group也不會(huì)報(bào)錯(cuò)域蜗,如果去掉defaultvalue=”2”且定義required=true則如果頁(yè)面不傳遞group則會(huì)報(bào)錯(cuò)巨双。

@PathVariable 綁定URI 模板變量值

@PathVariable用于將請(qǐng)求URL中的模板變量映射到功能處理方法的參數(shù)上

@RequestMapping(value="/useredit/{groupid}/{userid}",method={RequestMethod.GET,RequestMethod.POST})
    public String useredit(@PathVariable String groupid,@PathVariable String userid,Model model) throws Exception{
        //方法中使用@PathVariable獲取useried的值噪猾,使用model傳回頁(yè)面
        model.addAttribute("groupid", groupid);
        model.addAttribute("userid", userid);
        return"/user/useredit";
    }

如請(qǐng)求的URL 為“控制器URL/useredit/1/admin.action”,則自動(dòng)將URL中模板變量{groupid}和{userid}綁定到@PathVariable注解的同名參數(shù)上筑累,即入?yún)⒑?code>groupid=“1”畏妖、userid=“admin”

結(jié)果轉(zhuǎn)發(fā)

Redirect

Contrller方法返回結(jié)果重定向到一個(gè)url地址,如果方式:

return "redirect:/user/userlist.action";

redirect方式相當(dāng)于“response.sendRedirect()”疼阔,轉(zhuǎn)發(fā)后瀏覽器的地址欄變?yōu)檗D(zhuǎn)發(fā)后的地址,因?yàn)檗D(zhuǎn)發(fā)即執(zhí)行了一個(gè)新的requestresponse半夷。
由于新發(fā)起一個(gè)request原來(lái)的參數(shù)在轉(zhuǎn)發(fā)時(shí)就不能傳遞到下一個(gè)url婆廊,如果要傳參數(shù)可以/user/userlist.action后邊加參數(shù),如下:

/user/userlist.action?groupid=2&…..

forward

controller方法執(zhí)行后繼續(xù)執(zhí)行另一個(gè)controller方法巫橄。

return "forward:/user/userlist.action";

forward 方式相當(dāng)于“request.getRequestDispatcher().forward(request,response)”淘邻,轉(zhuǎn)發(fā)后瀏覽器地址欄還是原來(lái)的地址。轉(zhuǎn)發(fā)并沒(méi)有執(zhí)行新的request和response湘换,而是和轉(zhuǎn)發(fā)前的請(qǐng)求共用一個(gè)request和response宾舅。所以轉(zhuǎn)發(fā)前請(qǐng)求的參數(shù)在轉(zhuǎn)發(fā)后仍然可以讀取到。

如下例子:

@RequestMapping("/c")
    public String c(String groupid,UserVo userVo)throws Exception{
        
        System.out.println("...c...."+groupid+"...user..."+userVo.getUser());
        return "forward:/to/d.action";
    }
    
    @RequestMapping("/d")
    public String d(String groupid,UserVo userVo)throws Exception{
        
        System.out.println("...d...."+groupid+"...user..."+userVo.getUser());
        return "success";
    }

@RequestBody @ResponseBody實(shí)現(xiàn)json數(shù)據(jù)交互

@RequestBody

作用:

@RequestBody注解用于讀取http請(qǐng)求的內(nèi)容(字符串)彩倚,通過(guò)springmvc提供的HttpMessageConverter接口將讀到的內(nèi)容轉(zhuǎn)換為json筹我、xml等格式的數(shù)據(jù)并綁定到controller方法的參數(shù)上。

本例子應(yīng)用:

@RequestBody注解實(shí)現(xiàn)接收http請(qǐng)求的json數(shù)據(jù)帆离,將json數(shù)據(jù)轉(zhuǎn)換為java對(duì)象.

@ResponseBody

作用:

該注解用于將Controller的方法返回的對(duì)象蔬蕊,通過(guò)HttpMessageConverter接口轉(zhuǎn)換為指定格式的數(shù)據(jù)如:json,xml等,通過(guò)Response響應(yīng)給客戶端

本例子應(yīng)用:

@ResponseBody注解實(shí)現(xiàn)將controller方法返回對(duì)象轉(zhuǎn)換為json響應(yīng)給客戶端

請(qǐng)求json哥谷,響應(yīng)json實(shí)現(xiàn):

頁(yè)面上請(qǐng)求的是一個(gè)json串岸夯,頁(yè)面上實(shí)現(xiàn)時(shí)需要拼接一個(gè)json串提交到action。

Action將請(qǐng)求的json串轉(zhuǎn)為java對(duì)象们妥。SpringMVC利用@ResquesBody注解實(shí)現(xiàn).

Action將java對(duì)象轉(zhuǎn)為json猜扮,輸出到頁(yè)面。SpringMVC利用@ResponseBody注解實(shí)現(xiàn).

環(huán)境準(zhǔn)備

Springmvc默認(rèn)用MappingJacksonHttpMessageConverter對(duì)json數(shù)據(jù)進(jìn)行轉(zhuǎn)換监婶,需要加入jackson的包旅赢,如下:

配置:

在注解適配器中加入messageConverters

<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
    <property name="messageConverters">
        <list>
            <bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter"></bean>
        </list>
    </property>
</bean>

controller編寫

/**
     * 請(qǐng)求json單個(gè)對(duì)象,返回json單個(gè)對(duì)象
     * @param user
     * @return
     * @throws Exception
     */
    @RequestMapping("/requestjson")
    //@RequestBody接收json串自動(dòng)轉(zhuǎn)為user對(duì)象压储,@ResponseBody將user轉(zhuǎn)為json數(shù)據(jù)響應(yīng)給客戶端
    Public @ResponseBody User requestjson(@RequestBody User user)throws Exception{
        System.out.println(user);
        return user;
    }

頁(yè)面js方法編寫:

function request_json(){
         //將json對(duì)象傳成字符串
    var user = JSON.stringify({name: "張三", age: 3});
    alert(user);
      $.ajax(
        {
            type:'post',
            url:'${pageContext.request.contextPath}/requestjson.action',
            contentType:'application/json;charset=utf-8',//請(qǐng)求內(nèi)容為json
            data:user,
            success: function(data){
                alert(data.name);
            }
        }   
    )
  }

測(cè)試結(jié)果:

從上圖可以看出請(qǐng)求的數(shù)據(jù)是json格式

從上圖可以看出響應(yīng)的數(shù)據(jù)也是json格式鲜漩,json數(shù)據(jù)的內(nèi)容是從User對(duì)象轉(zhuǎn)換得來(lái)。

Form提交集惋,響應(yīng)json實(shí)現(xiàn)

采用form提交是最常用的作法孕似,通常有post和get兩種方法,響應(yīng)json數(shù)據(jù)是為了方便客戶端處理刮刑,實(shí)現(xiàn)如下:

環(huán)境準(zhǔn)備

同第一個(gè)例子

controller編寫

/
* 客戶端提交表單喉祭,服務(wù)端返回json
* @param user
* @return
* @throws Exception
/
@RequestMapping("/formsubmit")
Public @ResponseBody User formsubmit(User user)throws Exception{
System.out.println(user);
return user;
}
*

頁(yè)面js方法編寫:

function formsubmit(){
    var user = "name=張三&age=3";
    alert(user);
      $.ajax(
        {
            type:'post',//這里改為get也可以正常執(zhí)行
            url:'${pageContext.request.contextPath}/formsubmit.action',
            //ContentType沒(méi)指定將默認(rèn)為:application/x-www-form-urlencoded
            data:user,
            success:function(data){
            alert(data.name);
        }
            
        }   
    )
}

從上邊的js代碼看出养渴,已去掉ContentType的定義,ContentType默認(rèn)為:application/x-www-form-urlencoded格式泛烙。

測(cè)試結(jié)果:

從上圖可以看出請(qǐng)求的數(shù)據(jù)是標(biāo)準(zhǔn)的key/value格式理卑。

從上圖可以看出響應(yīng)的數(shù)據(jù)也是json格式,json數(shù)據(jù)的內(nèi)容是從User對(duì)象轉(zhuǎn)換得來(lái)蔽氨。

<mvc:annotation-driven />配置:

注解映射器和注解適配器可以使用 <mvc:annotation-driven /> 代替藐唠。

<mvc:annotation-driven /> 默認(rèn)注冊(cè)了注解映射器和注解適配器等bean。

如下:

以下配置可用 <mvc:annotation-driven /> 代替:

<!--注解映射器 -->   
    <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"/>
    <!--注解適配器 -->
    <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
        <property name="messageConverters">
        <list>
        <bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter"></bean>
        </list>
        </property>
    </bean>

15.攔截器

定義

Spring Web MVC 的處理器攔截器類似于Servlet 開(kāi)發(fā)中的過(guò)濾器Filter鹉究,用于對(duì)處理器進(jìn)行預(yù)處理和后處理宇立。
SpringMVC攔截器是針對(duì)mapping配置的攔截器

攔截器定義

實(shí)現(xiàn)HandlerInterceptor接口,如下:

Public class HandlerInterceptor1 implements HandlerInterceptor{

    /**
     * controller執(zhí)行前調(diào)用此方法
     * 返回true表示繼續(xù)執(zhí)行自赔,返回false中止執(zhí)行
     * 這里可以加入登錄校驗(yàn)妈嘹、權(quán)限攔截等
     */
    @Override
    Public boolean preHandle(HttpServletRequest request,
            HttpServletResponse response, Object handler) throws Exception {
        Return false;
    }
    /**
     * controller執(zhí)行后但未返回視圖前調(diào)用此方法
     * 這里可在返回用戶前對(duì)模型數(shù)據(jù)進(jìn)行加工處理,比如這里加入公用信息以便頁(yè)面顯示
     */
    @Override
    Public void postHandle(HttpServletRequest request,
            HttpServletResponse response, Object handler,
            ModelAndView modelAndView) throws Exception {
    }
    /**
     * controller執(zhí)行后且視圖返回后調(diào)用此方法
     * 這里可得到執(zhí)行controller時(shí)的異常信息
     * 這里可記錄操作日志绍妨,資源清理等
     */
    @Override
    Public void afterCompletion(HttpServletRequest request,
            HttpServletResponse response, Object handler, Exception ex)
            throws Exception {      
    }
}

攔截器配置

針對(duì)某種mapping配置攔截器

<bean
    class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping">
    <property name="interceptors">
        <list>
            <ref bean="handlerInterceptor1"/>
            <ref bean="handlerInterceptor2"/>
        </list>
    </property>
</bean>
    <bean id="handlerInterceptor1" class="springmvc.intercapter.HandlerInterceptor1"/>
    <bean id="handlerInterceptor2" class="springmvc.intercapter.HandlerInterceptor2"/>

針對(duì)所有mapping配置全局?jǐn)r截器

<!--攔截器 -->
<mvc:interceptors>
    <!--多個(gè)攔截器,順序執(zhí)行 -->
    <mvc:interceptor>
        <mvc:mapping path="/**"/>
        <bean class="cn.itcast.springmvc.filter.HandlerInterceptor1"></bean>
    </mvc:interceptor>
    <mvc:interceptor>
        <mvc:mapping path="/**"/>
        <bean class="cn.itcast.springmvc.filter.HandlerInterceptor2"></bean>
    </mvc:interceptor>
</mvc:interceptors>

正常流程測(cè)試

代碼:

定義兩個(gè)攔截器分別為:HandlerInterceptor1和HandlerInteptor2润脸,每個(gè)攔截器的preHandler方法都返回true

運(yùn)行流程

HandlerInterceptor1..preHandle..

HandlerInterceptor2..preHandle..

HandlerInterceptor2..postHandle..

HandlerInterceptor1..postHandle..

HandlerInterceptor2..afterCompletion..

HandlerInterceptor1..afterCompletion..

中斷流程測(cè)試

代碼:
定義兩個(gè)攔截器分別為:HandlerInterceptor1HandlerInteptor2他去。

運(yùn)行流程

HandlerInterceptor1preHandler方法返回false,HandlerInterceptor2返回true毙驯,運(yùn)行流程如下:

HandlerInterceptor1..preHandle..

從日志看出第一個(gè)攔截器的preHandler方法返回false后第一個(gè)攔截器只執(zhí)行了preHandler方法,其它兩個(gè)方法沒(méi)有執(zhí)行灾测,第二個(gè)攔截器的所有方法不執(zhí)行尔苦,且controller也不執(zhí)行了。

HandlerInterceptor1preHandler方法返回true行施,HandlerInterceptor2返回false允坚,運(yùn)行流程如下:

HandlerInterceptor1..preHandle..

HandlerInterceptor2..preHandle..

HandlerInterceptor1..afterCompletion..

從日志看出第二個(gè)攔截器的preHandler方法返回false后第一個(gè)攔截器的ostHandler沒(méi)有執(zhí)行,第二個(gè)攔截器的postHandlerafterCompletion沒(méi)有執(zhí)行蛾号,且controller也不執(zhí)行了稠项。

總結(jié):

preHandle按攔截器定義順序調(diào)用

postHandler按攔截器定義逆序調(diào)用

afterCompletion按攔截器定義逆序調(diào)用

postHandler在攔截器鏈內(nèi)所有攔截器返成功調(diào)用
afterCompletion只有preHandle返回true才調(diào)用

攔截器應(yīng)用

用戶身份認(rèn)證

Public class LoginInterceptor implements HandlerInterceptor{

    @Override
    Public boolean preHandle(HttpServletRequest request,
            HttpServletResponse response, Object handler) throws Exception {

        //如果是登錄頁(yè)面則放行
        if(request.getRequestURI().indexOf("login.action")>=0){
            return true;
        }
        HttpSession session = request.getSession();
        //如果用戶已登錄也放行
        if(session.getAttribute("user")!=null){
            return true;
        }
        //用戶沒(méi)有登錄挑戰(zhàn)到登錄頁(yè)面
        request.getRequestDispatcher("/WEB-INF/jsp/login.jsp").forward(request, response);
        
        return false;
    }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市鲜结,隨后出現(xiàn)的幾起案子展运,更是在濱河造成了極大的恐慌,老刑警劉巖精刷,帶你破解...
    沈念sama閱讀 218,755評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件拗胜,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡怒允,警方通過(guò)查閱死者的電腦和手機(jī)埂软,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)纫事,“玉大人勘畔,你說(shuō)我怎么就攤上這事所灸。” “怎么了炫七?”我有些...
    開(kāi)封第一講書人閱讀 165,138評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵爬立,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我万哪,道長(zhǎng)侠驯,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書人閱讀 58,791評(píng)論 1 295
  • 正文 為了忘掉前任奕巍,我火速辦了婚禮陵霉,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘伍绳。我一直安慰自己,他們只是感情好乍桂,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,794評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布冲杀。 她就那樣靜靜地躺著,像睡著了一般睹酌。 火紅的嫁衣襯著肌膚如雪权谁。 梳的紋絲不亂的頭發(fā)上即横,一...
    開(kāi)封第一講書人閱讀 51,631評(píng)論 1 305
  • 那天丢烘,我揣著相機(jī)與錄音躬厌,去河邊找鬼集灌。 笑死悴侵,一個(gè)胖子當(dāng)著我的面吹牛作喘,可吹牛的內(nèi)容都是我干的惧笛。 我是一名探鬼主播仲翎,決...
    沈念sama閱讀 40,362評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼壶辜,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼悯舟!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起砸民,我...
    開(kāi)封第一講書人閱讀 39,264評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤抵怎,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后岭参,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體反惕,經(jīng)...
    沈念sama閱讀 45,724評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評(píng)論 3 336
  • 正文 我和宋清朗相戀三年演侯,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了姿染。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,040評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡秒际,死狀恐怖盔粹,靈堂內(nèi)的尸體忽然破棺而出隘梨,到底是詐尸還是另有隱情,我是刑警寧澤舷嗡,帶...
    沈念sama閱讀 35,742評(píng)論 5 346
  • 正文 年R本政府宣布轴猎,位于F島的核電站,受9級(jí)特大地震影響进萄,放射性物質(zhì)發(fā)生泄漏捻脖。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,364評(píng)論 3 330
  • 文/蒙蒙 一中鼠、第九天 我趴在偏房一處隱蔽的房頂上張望可婶。 院中可真熱鬧,春花似錦援雇、人聲如沸矛渴。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 31,944評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)具温。三九已至,卻和暖如春筐赔,著一層夾襖步出監(jiān)牢的瞬間铣猩,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 33,060評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工茴丰, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留达皿,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,247評(píng)論 3 371
  • 正文 我出身青樓贿肩,卻偏偏與公主長(zhǎng)得像峦椰,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子汰规,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,979評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容

  • Spring Cloud為開(kāi)發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見(jiàn)模式的工具(例如配置管理们何,服務(wù)發(fā)現(xiàn),斷路器控轿,智...
    卡卡羅2017閱讀 134,659評(píng)論 18 139
  • 從三月份找實(shí)習(xí)到現(xiàn)在冤竹,面了一些公司,掛了不少茬射,但最終還是拿到小米鹦蠕、百度、阿里在抛、京東钟病、新浪、CVTE、樂(lè)視家的研發(fā)崗...
    時(shí)芥藍(lán)閱讀 42,253評(píng)論 11 349
  • Spring mvc 框架 DispatcherServlet前端控制器 ---- 整個(gè)流程控制的中心肠阱,由它調(diào)用其...
    蕊er閱讀 705評(píng)論 0 0
  • Spring Boot 參考指南 介紹 轉(zhuǎn)載自:https://www.gitbook.com/book/qbgb...
    毛宇鵬閱讀 46,822評(píng)論 6 342
  • 攝影畸變 如圖是廣角鏡頭拍攝時(shí), 經(jīng)常出現(xiàn)的畸變現(xiàn)象示意 百度百科: 拍攝四方形的物體時(shí)噪伊,使周圍拍成卷翹或膨鼓的現(xiàn)...
    馬克圖布了閱讀 21,566評(píng)論 0 1