springmvc

一旭咽、SpringMVC

1.1 引言1.2 MVC架構(gòu)1.2.1 概念1.2.2 好處

二、開(kāi)發(fā)流程

2.1 導(dǎo)入依賴2.2 配置核心(前端)控制器2.3 后端控制器2.4 配置文件2.5 訪問(wèn)

三熊锭、接收請(qǐng)求參數(shù)

3.1 基本類型參數(shù)3.2 實(shí)體收參【重點(diǎn)】3.3 數(shù)組收參3.4 集合收參 【了解】3.5 路徑參數(shù)3.6 中文亂碼

四、跳轉(zhuǎn)

4.1 轉(zhuǎn)發(fā)4.2 重定向4.3 跳轉(zhuǎn)細(xì)節(jié)

五、傳值

5.1 Request和Session5.2 JSP中取值5.3 Model5.4 ModelAndView5.5 @SessionAttributes

六袄琳、靜態(tài)資源

6.1 靜態(tài)資源問(wèn)題6.2 解決方案16.3 解決方案26.4 解決方案3

七漾橙、Json處理

7.1 導(dǎo)入依賴7.2 使用@ResponseBody7.3 使用@RestController7.4 使用@RequestBody7.4.1 定義Handler7.4.2 Ajax發(fā)送json7.5 Jackson常用注解7.5.1 日期格式化7.5.2 屬性名修改7.5.3 屬性忽略7.5.4 null和empty屬性排除7.5.5 自定義序列化7.6 FastJson7.6.1 導(dǎo)入依賴7.6.2 安裝FastJson7.6.3 使用7.6.4 常用注解

八杆融、異常解析器

8.1 現(xiàn)有方案,分散處理8.2 異常解析器霜运,統(tǒng)一處理

九脾歇、攔截器

9.1 作用9.2 定義攔截器9.3 配置攔截路徑

十蒋腮、上傳

10.1 導(dǎo)入jar10.2 表單10.3 上傳解析器10.4 Handler

十一、下載

11.1 超鏈11.2 Handler

十二藕各、驗(yàn)證碼

12.1 作用12.2 導(dǎo)入jar12.3 聲明驗(yàn)證碼組件12.4 Page

十三池摧、REST

13.1 開(kāi)發(fā)風(fēng)格13.2 優(yōu)點(diǎn)13.3 使用13.3.1 定義Rest風(fēng)格的 Controller13.3.2 Ajax請(qǐng)求

十四、跨域請(qǐng)求

14.1 域14.2 Ajax跨域問(wèn)題14.3 解決方案

十五激况、SpringMVC執(zhí)行流程

十六作彤、Spring整合

16.1 整合思路16.2 整合技巧

一、SpringMVC

1.1 引言

java開(kāi)源框架乌逐,Spring Framework的一個(gè)獨(dú)立模塊竭讳。

MVC框架,在項(xiàng)目中開(kāi)辟M(fèi)VC層次架構(gòu)? ?

對(duì)控制器中的功能 包裝 簡(jiǎn)化 擴(kuò)展踐行工廠模式,功能架構(gòu)在工廠之上

1.2 MVC架構(gòu)

1.2.1 概念

名稱職責(zé)

Model模型:即業(yè)務(wù)模型浙踢,負(fù)責(zé)完成業(yè)務(wù)中的數(shù)據(jù)通信處理绢慢,對(duì)應(yīng)項(xiàng)目中的 service和dao

View視圖:渲染數(shù)據(jù),生成頁(yè)面洛波。對(duì)應(yīng)項(xiàng)目中的Jsp

Controller控制器:直接對(duì)接請(qǐng)求胰舆,控制MVC流程,調(diào)度模型奋岁,選擇視圖思瘟。對(duì)應(yīng)項(xiàng)目中的Servlet

1.2.2 好處

MVC是現(xiàn)下軟件開(kāi)發(fā)中的最流行的代碼結(jié)構(gòu)形態(tài);

人們根據(jù)負(fù)責(zé)的不同邏輯,將項(xiàng)目中的代碼分成 M V C 3個(gè)層次;

層次內(nèi)部職責(zé)單一闻伶,層次之間耦合度低;

符合低耦合 高內(nèi)聚的設(shè)計(jì)理念滨攻。也實(shí)際有利于項(xiàng)目的長(zhǎng)期維護(hù)。

二蓝翰、開(kāi)發(fā)流程

2.1 導(dǎo)入依賴

????<dependency>

????????????<groupId>org.springframework</groupId>

????????????<artifactId>spring-webmvc</artifactId>

????????????<version>5.1.6.RELEASE</version>

????</dependency>

2.2 配置核心(前端)控制器

作為一個(gè)MVC框架光绕,首先要解決的是:如何能夠收到請(qǐng)求!

所以MVC框架大都會(huì)設(shè)計(jì)一款前端控制器畜份,選型在 Servlet 或 Filter兩者之一,在框架最前沿率先工作诞帐,接收所有請(qǐng)求。

此控制器在接收到請(qǐng)求后爆雹,還會(huì)負(fù)責(zé)springMVC的核心的調(diào)度管理停蕉,所以既是前端又是核心。

<servlet>

????<servlet-name>mvc</servlet-name>

????<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>

????<!-- 局部參數(shù):聲明配置文件位置 -->

????<init-param>

????????<param-name>contextConfigLocation</param-name>

????????<param-value>classpath:mvc.xml</param-value>

????</init-param>

????<!-- Servlet啟動(dòng)時(shí)刻:可選 -->

????<load-on-startup>1</load-on-startup>

</servlet>

<servlet-mapping>

????<servlet-name>mvc</servlet-name>

????<url-pattern>/</url-pattern>

</servlet-mapping>

2.3 后端控制器

等價(jià)于之前定義的Servlet

@Controller//聲明這是一個(gè)控制器

@RequestMapping("/hello")//訪問(wèn)路徑 钙态,等價(jià)于url-pattern

publicclassHelloController{

? ? @RequestMapping("/test1")//訪問(wèn)路徑

? ? publicStringhello1(){

? ? ? ? System.out.println("hello world");

? ? ? ? return"index";// 跳轉(zhuǎn):/index.jsp ?

? ? }

? ? @RequestMapping("/test2")//訪問(wèn)路徑

? ? publicStringhello2(){

? ? ? ? System.out.println("hello c9");

? ? ? ? return"views/users";//? 跳轉(zhuǎn):/views/user.jsp

? ? }

}

2.4 配置文件

默認(rèn)名稱:核心控制器名-servet.xml? ? 默認(rèn)位置:WEB-INF

隨意名稱:mvc.xml? ? ? ? ? 隨意位置:resources? ? 但需要配置在核心控制器中

<beans xmlns="http://www.springframework.org/schema/beans"

? ? ? ? xmlns:context="http://www.springframework.org/schema/context"

? ? ? ? xmlns:mvc="http://www.springframework.org/schema/mvc"

? ? ? ? xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

? ? ? ? xsi:schemaLocation="http://www.springframework.org/schema/beans

? ? ? ? ? ? ? ? ? ? ? ? ? ? http://www.springframework.org/schema/beans/spring-beans.xsd

? ? ? ? ? ? ? ? ? ? ? ? ? ? http://www.springframework.org/schema/context

? ? ? ? ? ? ? ? ? ? ? ? ? ? http://www.springframework.org/schema/context/spring-context.xsd

? ? ? ? ? ? ? ? ? ? ? ? ? ? http://www.springframework.org/schema/mvc

? ? ? ? ? ? ? ? ? ? ? ? ? ? http://www.springframework.org/schema/mvc/spring-mvc.xsd">

?

? ? <!-- 告知springmvc? 哪些包中 存在 被注解的類 -->

? ? <context:component-scanbase-package="com.qf.controller"></context:component-scan>

? ? <!-- 注冊(cè)注解開(kāi)發(fā)驅(qū)動(dòng) -->

? ? <mvc:annotation-driven></mvc:annotation-driven>

? ? <!-- 視圖解析器

? ? 作用:1.捕獲后端控制器的返回值="index"

? ? 2.解析: 在返回值的前后 拼接 ==> "/index.jsp"

? ? -->

? ? <beanclass="org.springframework.web.servlet.view.InternalResourceViewResolver">

? ? ? ? <!-- 前綴 -->

? ? ? ? <propertyname="prefix"value="/"></property>

? ? ? ? <!-- 后綴 -->

? ? ? ? <propertyname="suffix"value=".jsp"></property>

? ? </bean>

</beans>

2.5 訪問(wèn)

http://localhost:8989/hello/test1

http://localhost:8989/hello/test2

三慧起、接收請(qǐng)求參數(shù)

3.1 基本類型參數(shù)

請(qǐng)求參數(shù)和方法的形參 同名即可

springMVC默認(rèn)可以識(shí)別的日期字符串格式為: YYYY/MM/dd HH:mm:ss通過(guò)@DateTimeFormat可以修改默認(rèn)日志格式

// id? name gender

// http://localhost:8989/xxx/../test1?id=1&name=zzz&gender=false&birth=2018-12-12 12:20:30

@RequestMapping("/test1")

publicStringtestParam1(Integerid,

Stringname,

Booleangender,

@DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")Datebirth){

System.out.println("test param1");

return"index";

}

3.2 實(shí)體收參【重點(diǎn)】

請(qǐng)求參數(shù)和實(shí)體的屬性 同名即可

publicclassUser{

? ? privateIntegerid;

? ? privateStringname;

? ? @DateTimeFormat(pattern="yyyy-MM-dd")

? ? privateDatebirth;

? ? privateBooleangender;

? ? //set/get ...

}

?

//http://localhost:8989/.../test2?id=1&name=zzz&gender=false&birth=2018-12-12 12:20:30

@RequestMapping("/test2")

publicStringtestParam2(Useruser){

System.out.println("test param2");

System.out.println("user:"+user);

return"index";

}

3.3 數(shù)組收參

簡(jiǎn)單類型的 數(shù)組

<form>

?? ......

<inputtype="checkbox"name="hobby"value="fb"/>足球

<inputtype="checkbox"name="hobby"value="bb"/>籃球

<inputtype="checkbox"name="hobby"value="vb"/>排球


</form>

//http://localhost:8989/.../test3?hobby=football&hobby=basketball

@RequestMapping("/test3")

publicStringtestParam3(String[]hobby){

for(Stringh:hobby){

System.out.print(h+" ");

?? }

return"index";

}

3.4 集合收參 【了解】

publicclassUserList{

? ? //private User[] users;

? ? privateList<User>users;

? ? //set/get..

}

?

// <input type="text" name="users[0].id"/>

// post請(qǐng)求:http://...?users[0].id=1&users[0].name=zhangsan&users[0].birth=2018-12-12&users[1].id=2&....

@RequestMapping("/test4")

publicStringtestParam4(UserListuserList){

for(Useruser:userList.getUsers()){

System.out.println(user);

?? }

return"index";

}

3.5 路徑參數(shù)

// {id} 定義名為id的路徑;【/hello/{id}】的匹配能力和【/hello/*】等價(jià)

// http://localhost:8989/.../hello/10 ? {id}匹配到10

@RequestMapping("/hello/{id}")

// @PathVariable將{id}路徑匹配到值賦給id參數(shù)

// 路徑名和參數(shù)名相同則@PathVariable("id")可簡(jiǎn)寫(xiě)為 @PathVariable

publicStringtestParam5(@PathVariable("id")Integerid){

System.out.println("id:"+id);

return"index";

}

?

// http://localhost:8989/.../hello/tom ? {username}匹配到tom

@RequestMapping("/hello/{username}")

publicStringtestParam6(@PathVariable("username")Stringname){//將{username}路徑匹配到的值賦給name參數(shù)

System.out.println("username:"+name);

return"index";

}

3.6 中文亂碼

首先册倒,頁(yè)面中字符集統(tǒng)一

????????JSP : <%@pagepageEncoding="utf-8"%>

????????HTML :<metacharset="UTF-8">

其次蚓挤,tomcat中字符集設(shè)置,對(duì)get請(qǐng)求中,中文參數(shù)亂碼有效

????????Tomcat配置:URIEncoding=utf-8

最后灿意,設(shè)置此filter估灿,對(duì)post請(qǐng)求中,中文參數(shù)亂碼有效

<!-- 此過(guò)濾器會(huì)進(jìn)行:request.setCharactorEncoding("utf-8"); -->

<filter>

<filter-name>encoding</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>encoding</filter-name>

<url-pattern>/*</url-pattern>

</filter-mapping>

四缤剧、跳轉(zhuǎn)

4.1 轉(zhuǎn)發(fā)

@RequestMapping("/forw")

class ForwardController{

? ? @RequestMapping("/test1")

? ? public String testForward(){

? ? ? ? System.out.println("test forward1");

? ? ? ? // 轉(zhuǎn)發(fā)跳轉(zhuǎn) /views/users.jsp

? ? ? ? // return "views/users";//和下一行等價(jià)

? ? ? ? return "forward:/views/users.jsp";

? ? }

? ? @RequestMapping("/test2")

? ? public String testForward2(){

? ? ? ? System.out.println("test forward2");

? ? ? ? //轉(zhuǎn)發(fā)到? /forw/test1

? ? ? ? //return "forward:test1";//相對(duì)路徑(轉(zhuǎn)發(fā)到本類中的test1)

? ? ? ? //轉(zhuǎn)發(fā)到? /forw/test1

? ? ? ? return "forward:/forw/test1"; //絕對(duì)路徑

? ? }

}

4.2 重定向

@RequestMapping("/redir")

classRedirectController{

@RequestMapping("/test1")

publicStringtestRedirect1(){

System.out.println("test redirect1");

//重定向到 /redir/test1

//return "redirect:test1"; //相對(duì)路徑(轉(zhuǎn)發(fā)到本類中的test1)

return"redirect:/redir/test1";//絕對(duì)路徑

?? }

@RequestMapping("/test2")

publicStringtestRedirect2(){

System.out.println("test redirect2");

//重定向到 /views/users.jsp

return"redirect:/view/user.jsp";

?? }

}

4.3 跳轉(zhuǎn)細(xì)節(jié)

????在增刪改之后馅袁,為了防止請(qǐng)求重復(fù)提交,重定向跳轉(zhuǎn)

????在查詢之后荒辕,可以做轉(zhuǎn)發(fā)跳轉(zhuǎn)

五司顿、傳值

????C得到數(shù)據(jù)后,跳轉(zhuǎn)到V兄纺,并向V傳遞數(shù)據(jù)。進(jìn)而V中可以渲染數(shù)據(jù)化漆,讓用戶看到含有數(shù)據(jù)的頁(yè)面

????轉(zhuǎn)發(fā)跳轉(zhuǎn):Request作用域

????重定向跳轉(zhuǎn):Session作用域

5.1 Request和Session

//形參中 即可獲得 request 和 session對(duì)象

@RequestMapping("/test1")

publicStringtestData(HttpSessionsession,HttpServletRequestreq估脆,Integerid){

session.setAttribute("user",newUser());

req.setAttribute("age",18);

req.setAttribute("users",Arrays.asList(newUser(),newUser()));

//return "test2";

return"forward:/WEB-INF/test2.jsp";

}

5.2 JSP中取值

建議:重點(diǎn)復(fù)習(xí) EL? JSTL

????//jsp中用EL表達(dá)式 取值即可

????<fmt:formatDatevalue="${sessionScope.user.birth}"pattern="yyyy-MM-dd"/><br/>

????${sessionScope.user.birth}<br>

? ? ${requestScope.age}

5.3 Model

//model中的數(shù)據(jù),會(huì)在V渲染之前座云,將數(shù)據(jù)復(fù)制一份給request

@RequestMapping("/test")

publicStringtestData(Modelmodel){

model.addAttribute("name","張三");

return"index";

}

?

//jsp中用EL表達(dá)式 取值即可

${requestScope.name}

5.4 ModelAndView

//modelandview 可以集中管理 跳轉(zhuǎn)和數(shù)據(jù)

@RequestMapping("/test")

publicModelAndViewtestData(){//返回值類型為ModelAndView

//新建ModelAndView對(duì)象

ModelAndViewmv=newModelAndView();

// 設(shè)置視圖名疙赠,即如何跳轉(zhuǎn)

mv.setViewName("forward:/index.jsp");

// 增加數(shù)據(jù)

mv.addObject("age",18);

returnmv;

}

?

//jsp中用EL表達(dá)式 取值即可

${requestScope.age}

5.5 @SessionAttributes

@SessionAttributes({"gender","name"})? :model中的 name和gender 會(huì)存入session中

SessionStatus 移除session

@Controller

@SessionAttributes({"gender","name"})// model中的 name和gender 會(huì)存入session中

publicclassUserController{

?

@RequestMapping("/hello")

publicStringhello(Modelm){

m.addAttribute("gender",true);// 會(huì)存入session

mv.addObject("name","zhj");// 會(huì)存入session

return"index";

?? }


@RequestMapping("/hello2")

publicStringhello(SessionStatusstatus){

// 移除通過(guò)SessionAttributes存入的session

status.setComplete();

return"index";

?? }

}

六、靜態(tài)資源

6.1 靜態(tài)資源問(wèn)題

靜態(tài)資源:html朦拖,js文件圃阳,css文件,圖片文件

靜態(tài)文件沒(méi)有url-pattern,所以默認(rèn)是訪問(wèn)不到的璧帝,之所以可以訪問(wèn)捍岳,是因?yàn)椋瑃omcat中有一個(gè)全局的servlet:org.apache.catalina.servlets.DefaultServlet睬隶,它的url-pattern是 "/",是全局默認(rèn)的Servlet.? 所以每個(gè)項(xiàng)目中不能匹配的靜態(tài)資源的請(qǐng)求锣夹,有這個(gè)Servlet來(lái)處理即可。

但苏潜,在SpringMVC中DispatcherServlet也采用了 “/” 作為url-pattern, 則項(xiàng)目中不會(huì)再使用全局的Serlvet银萍,則靜態(tài)資源不能完成訪問(wèn)。

6.2 解決方案1

DispathcerServlet采用其他的url-pattern

此時(shí)恤左,所有訪問(wèn)handler的路徑都要以 action結(jié)尾L健!

????<servlet>

? ????????<servlet-name>mvc9</servlet-name>

? ????????<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>

????</servlet>

????<servlet-mapping>

????????<servlet-name>mvc9</servlet-name>

????????<url-pattern>*.action</url-pattern>

????</servlet-mapping>

6.3 解決方案2

DispathcerServlet的url-pattern依然采用 "/",但追加配置

<!--

額外的增加一個(gè)handler飞袋,且其requestMapping:? "/**" 可以匹配所有請(qǐng)求戳气,但是優(yōu)先級(jí)最低

所以如果其他所有的handler都匹配不上,請(qǐng)求會(huì)轉(zhuǎn)向 "/**" ,恰好授嘀,這個(gè)handler就是處理靜態(tài)資源的

處理方式:將請(qǐng)求轉(zhuǎn)會(huì)到tomcat中名為default的Servlet

-->

<mvc:default-servlet-handler/>

6.4 解決方案3

mapping是訪問(wèn)路徑物咳,location是靜態(tài)資源存放的路徑

將/html/** 中 /**匹配到的內(nèi)容,拼接到 /hhh/后http://..../html/a.html? 訪問(wèn) /hhh/a.html

<mvc:resourcesmapping="/html/**"location="/hhh/"/>

七、Json處理

7.1 導(dǎo)入依賴

<!-- Jackson springMVC默認(rèn)的Json解決方案選擇是 Jackson览闰,所以只需要導(dǎo)入jackson的jar芯肤,即可使用。-->

????<dependency>

????????<groupId>com.fasterxml.jackson.core</groupId>

????????<artifactId>jackson-databind</artifactId>

????<version>2.9.8</version>

</dependency>

7.2 使用@ResponseBody

@Controller

publicclassJsonController{

? ? @RequestMapping("/test1")

@ResponseBody//將handler的返回值压鉴,轉(zhuǎn)換成json(jackson),并將json響應(yīng)給客戶端崖咨。

publicUserhello1(){

System.out.println("hello world");

Useruser=newUser();

returnuser;

?? }

// @ResponseBody還可以用在handler的返回值上

@RequestMapping("/test2")

public@ResponseBodyList<User>hello2(){

System.out.println("hello world");

List<User>users=Arrays.asList(newUser(),newUser());

returnusers;

?? }

// 如果返回值已經(jīng)是字符串,則不需要轉(zhuǎn)json油吭,直接將字符串響應(yīng)給客戶端

@RequestMapping(value="/test3",produces="text/html;charset=utf-8")//produces 防止中文亂碼

@ResponseBody

publicStringhello2(){

System.out.println("hello world");

return"你好";

?? }

}

7.3 使用@RestController

Controller類上加了@RestController注解击蹲,等價(jià)于在類中的每個(gè)方法上都加了@ResponseBody

@Controller

@RestController

publicclassJsonController{

@RequestMapping("/test1")

publicUserhello1(){

System.out.println("hello world");

Useruser=newUser();

returnuser;

?? }

//@ResponseBody還可以用在handler的返回值上

@RequestMapping("/test2")

publicList<User>hello2(){

System.out.println("hello world");

List<User>users=Arrays.asList(newUser(),newUser());

returnusers;

?? }

}

7.4 使用@RequestBody

? ??@RequestBody, 接收J(rèn)son參數(shù)

7.4.1 定義Handler

classUser{

privateIntegerid;

privateStringname;

privateBooleangender;

//set get

}

@RequestMapping("/users")

publicStringaddUser(@RequestBodyUseruser){//@RequestBody將請(qǐng)求體中的json數(shù)據(jù)轉(zhuǎn)換為java對(duì)象

????System.out.println("cap2");

????System.out.println("Post user :"+user);

????return"index";

}

7.4.2 Ajax發(fā)送json

varxhr=newXMLHttpRequest();

xhr.open("post","${pageContext.request.contextPath}/users?"+newDate().getTime());

xhr.setRequestHeader("content-type","application/json");//設(shè)置請(qǐng)求頭

xhr.send('{"id":1,"name":"shine","gender":"true"}');//傳遞json串

//ajax

varuser={id:1,name:"shine"};

$.ajax({

url:'${pageContext.request.contextPath}/json2/test4',

type:'post',

contentType:"application/json",//聲明請(qǐng)求參數(shù)類型為 json

data:JSON.stringify(user),// 轉(zhuǎn)換js對(duì)象成json

success:function(ret){

console.log(ret);

?? }

});

7.5 Jackson常用注解

7.5.1 日期格式化

@JsonFormat(pattern="yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")

publicclassUser{

? ? privateIntegerid;

? ? privateStringname;

? ? @JsonFormat(pattern="yyyy-MM-dd HH:mm:ss",timezone="GMT+8")

? ? privateDatebirth;

?? ....

get/set

}

7.5.2 屬性名修改

@JsonProperty("new_name")

publicclassUser{

? ? @JsonProperty("new_id")//不再使用原屬性名,而是 "new_id"

privateIntegerid;

? ? privateStringname;

?? ....

get/set

}

輸出的json:{“new_id”:xx,"name":"xx"}

7.5.3 屬性忽略

@JsonIgnore

publicclassUser{

privateIntegerid;

@JsonIgnore// 生成json時(shí)婉宰,忽略此屬性

? ? privateStringname;

?? ....

get/set

}

輸出json時(shí): {"id":xx}

7.5.4 null和empty屬性排除

Jackson 默認(rèn)會(huì)輸出null值的屬性歌豺,如果不需要,可以排除心包。

@JsonInclude(JsonInclude.Include.NON_NULL) //null值 屬性不輸出@JsonInclude(value= JsonInclude.Include.NON_EMPTY) // empty屬性不輸出( 空串类咧,長(zhǎng)度為0的集合,null值)

publicclassUser{

privateIntegerid;

@JsonInclude(JsonInclude.Include.NON_NULL)// 若"name==null" 忽略此屬性

? ? privateStringname;

@JsonInclude(value=JsonInclude.Include.NON_EMPTY)// 若hobby長(zhǎng)度為0或==null 忽略此屬性

privateList<String>hobby;

?? ....

get/set

}

如果name=null,且hobby長(zhǎng)度為0蟹腾,則輸出json時(shí):{"id":xx}

7.5.5 自定義序列化

@JsonSerialize(using = MySerializer.class) // 使用MySerializer輸出某屬性

publicclassUser{

privateIntegerid;

privateStringname;

@JsonSerialize(using=MySerializer.class)

privateDoublesalary=10000.126;//在輸出此屬性時(shí)痕惋,使用MySerializer輸出

?? ....

get/set

}

則輸出json時(shí):{"id":xx,"name":"xxx","salary":10000.13}

publicclassMySerializerextendsJsonSerializer<Double>{

?

// value即 Double salary的值

@Override

publicvoidserialize(Doublevalue,JsonGeneratorgen,SerializerProviderserializers)throwsIOException{

// 將Double salary的值 四舍五入

Stringnumber=BigDecimal.valueOf(value).setScale(2,BigDecimal.ROUND_HALF_UP).toString();

// 輸出 四舍五入后的值

gen.writeNumber(number);

?? }

}

7.6 FastJson

7.6.1 導(dǎo)入依賴

<!-- FastJson -->

<dependency>

????<groupId>com.alibaba</groupId>

????<artifactId>fastjson</artifactId>

????<version>1.2.54</version>

</dependency>

7.6.2 安裝FastJson

<mvc:annotation-driven>

<!-- 安裝FastJson,轉(zhuǎn)換器 -->

<mvc:message-converters>

????<bean class="com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter">

????<!-- 聲明轉(zhuǎn)換類型:json -->

????<propertyname="supportedMediaTypes">

? ? ? ? ?<list>

????????????????<value>application/json</value>

????????</list>

? ? ?</property>

????</bean>

</mvc:message-converters>

</mvc:annotation-driven>

7.6.3 使用

@ResponseBody? @RequestBody @RestController 使用方法不變

7.6.4 常用注解

日期格式化:@JSONField(format="yyyy/MM/dd")

屬性名修改:@JSONField(name="birth")

忽略屬性:@JSONField(serialize = false)

包含null值:@JSONField(serialzeFeatures = SerializerFeature.WriteMapNullValue)? 默認(rèn)會(huì)忽略所有null值,有此注解會(huì)輸出null

@JSONField(serialzeFeatures = SerializerFeature.WriteNullStringAsEmpty)? null的String輸出為""

自定義序列化:@JSONField(serializeUsing = MySerializer2.class)

publicclassUserimplementsSerializable{

? ? @JSONField(serialize=false)

privateIntegerid;

@JSONField(name="NAME",serialzeFeatures=SerializerFeature.WriteNullStringAsEmpty)

? ? privateStringname;

@JSONField(serialzeFeatures=SerializerFeature.WriteMapNullValue)

privateStringcity;

? ? @JSONField(format="yyyy/MM/dd")

? ? privateDatebirth;

@JSONField(serializeUsing=MySerializer2.class)

privateDoublesalary;

? ? ...

}

publicclassMySerializer2implementsObjectSerializer{

@Override

publicvoidwrite(JSONSerializerserializer,Objectobject,ObjectfieldName,TypefieldType,

intfeatures)throwsIOException{

Doublevalue=(Double)object;// salary屬性值

Stringtext=value+"元";// 在salary后拼接 “元”

serializer.write(text);// 輸出拼接后的內(nèi)容

?? }

}

newUser(1,null娃殖,null值戳,newDate(),100.5);

// 如上對(duì)象炉爆,轉(zhuǎn)換json:

{NAME:""堕虹,city:null,"birth":"2020/12/12"芬首,"salary":"100.5元"}

?

八鲫凶、異常解析器

8.1 現(xiàn)有方案,分散處理

Controller中的每個(gè)Handler自己處理異常

此種處理方案衩辟,異常處理邏輯螟炫,分散在各個(gè)handler中,不利于集中管理

publicStringxxx(){

try{

? ? ...

}catch(Exception1e){

? ? e.printStackTrace();

return"redirect:/xx/error1";

}catch(Exception2e){

? ? e.printStackTrace();

return"redirect:/xx/error2";

?? }

}

8.2 異常解析器艺晴,統(tǒng)一處理

Controller中的每個(gè)Handler不再自己處理異常昼钻,而是直接throws所有異常。

定義一個(gè)“異常解析器” 集中捕獲處理 所有異常

此種方案封寞,在集中管理異常方面然评,更有優(yōu)勢(shì)!

publicclassMyExResolverimplementsHandlerExceptionResolver{

? ? /**

? ? * 異常解析器:主體邏輯

? ? * 執(zhí)行時(shí)刻:當(dāng)handler中拋出異常時(shí)狈究,會(huì)執(zhí)行:捕獲異常碗淌,并可以跳到錯(cuò)誤頁(yè)面

? ? */

? ? @Override

? ? publicModelAndViewresolveException(HttpServletRequestrequest,

? ? ? ? ? ? HttpServletResponseresponse,Objecthandler,Exceptionex) {

? ? ? ? ex.printStackTrace();//打印異常棧

? ? ? ? //創(chuàng)建一個(gè)ModelAndView

? ? ? ? ModelAndViewmv=newModelAndView();

? ? ? ? //識(shí)別異常

? ? ? ? if(exinstanceofException1) {

? ? ? ? ? ? mv.setViewName("redirect:/xxx/error1");

? ? ? ? }elseif(exinstanceofException2){

? ? ? ? ? ? mv.setViewName("redirect:/xxx/error2");

? ? ? ? }else{

? ? ? ? ? ? mv.setViewName("redirect:/xxx/error");

? ? ? ? }

? ? ? ? returnmv;

? ? }

}

<!-- 聲明異常解析器 -->? ?

<beanclass="com.baizhi.exception.resolver.MyExResolver"></bean>

九、攔截器

9.1 作用

作用:抽取handler中的冗余功能

9.2 定義攔截器

執(zhí)行順序: preHandle--postHandle--afterCompletion

publicclassMyInter1implementsHandlerInterceptor{

? ? //主要邏輯:在handler之前執(zhí)行:抽取handler中的冗余代碼

? ? @Override

? ? publicbooleanpreHandle(HttpServletRequestrequest,

? ? ? ? ? ? HttpServletResponseresponse,Objecthandler)throwsException{

? ? ? ? System.out.println("pre~~~");

/*

response.sendRedirect("/springMVC_day2/index.jsp");//響應(yīng)

return false;//中斷請(qǐng)求

*/

? ? ? ? returntrue;//放行,后續(xù)的攔截器或handler就會(huì)執(zhí)行

? ? }

? ? //在handler之后執(zhí)行:進(jìn)一步的響應(yīng)定制

? ? @Override

? ? publicvoidpostHandle(HttpServletRequestrequest,

? ? ? ? ? ? HttpServletResponseresponse,Objecthandler,

? ? ? ? ? ? ModelAndViewmodelAndView)throwsException{

? ? ? ? System.out.println("post~~");

? ? }

? ? //在頁(yè)面渲染完畢之后亿眠,執(zhí)行:資源回收

? ? @Override

? ? publicvoidafterCompletion(HttpServletRequestrequest,

? ? ? ? ? ? HttpServletResponseresponse,Objecthandler,Exceptionex)

? ? ? ? ? ? throwsException{

? ? ? ? System.out.println("after~~");

? ? }

}

9.3 配置攔截路徑

<mvc:interceptors>

<mvc:interceptor>

<mvc:mappingpath="/inter/test1"/>

<mvc:mappingpath="/inter/test2"/>

<mvc:mappingpath="/inter/test*"/><!-- test開(kāi)頭 -->

<mvc:mappingpath="/inter/**"/><!-- /** 任意多級(jí)任意路徑 -->

<mvc:exclude-mappingpath="/inter/a/**"/><!--不攔截此路徑-->

<beanclass="com.baizhi.interceptor.MyInter1"></bean><!--攔截器類-->

</mvc:interceptor>

</mvc:interceptors>

十碎罚、上傳

10.1 導(dǎo)入jar

<dependency>

????<groupId>commons-io</groupId>

????<artifactId>commons-io</artifactId>

????<version>2.4</version>

</dependency>

?

<dependency>

????<groupId>commons-fileupload</groupId>

????<artifactId>commons-fileupload</artifactId>

????<version>1.3.3</version>

<exclusions>

<exclusion>

????<groupId>javax.servlet</groupId>

????<artifactId>servlet-api</artifactId>

</exclusion>

</exclusions>

</dependency>

10.2 表單

<formaction="${pageContext.request.contextPath }/upload/test1"method="post" enctype="multipart/form-data">

????file:<inputtype="file"name="source"/><br>

????<inputtype="submit"value="提交"/>

</form>

10.3 上傳解析器

<!-- 上傳解析器? id必須是:“multipartResolver” -->

<beanid="multipartResolver"? class="org.springframework.web.multipart.commons.CommonsMultipartResolver">

<!-- 最大可上傳的文件大小? 單位:byte? 超出后會(huì)拋出MaxUploadSizeExceededException異常,可以異常解析器捕獲 -->

<propertyname="maxUploadSize"value="1048576"></property>

</bean>

10.4 Handler

@RequestMapping("/test1")

publicStringhello1(Stringusername,MultipartFilesource,HttpSessionsession) {

//文件的原始名稱

Stringfilename=source.getOriginalFilename();

//定制全局唯一的命名

Stringunique=UUID.randomUUID().toString();

//獲得文件的后綴

Stringext=FilenameUtils.getExtension(filename);//abc.txt ? txt ?? hello.html? html

//定制全局唯一的文件名

StringuniqueFileName=unique+"."+ext;

System.out.println("唯一的文件名:"+uniqueFileName);

?

//文件的類型

Stringtype=source.getContentType();

System.out.println("filename:"+filename+" type:"+type);

?

//獲得 upload_file的磁盤(pán)路徑 ==> 在webapp目錄下創(chuàng)建一個(gè)目錄"upload_file",且此目錄初始不要為空纳像,否則編譯時(shí)被忽略

Stringreal_path=session.getServletContext().getRealPath("/upload_file");

System.out.println("real_path:"+real_path);

?

//將上傳的文件荆烈,存入磁盤(pán)路徑中

//source.transferTo(new File("d:/xxxx/xxxx/xx.jpg"))

source.transferTo(newFile(real_path+"\\"+uniqueFileName));

return"index";

}

十一、下載

11.1 超鏈

<ahref="${pageContext.request.contextPath}/download/test1?name=Koala.jpg">下載</a>

11.2 Handler

@RequestMapping("/test1")

publicvoidhello1(Stringname,HttpSessionsession,HttpServletResponseresponse){

System.out.println("name:"+name);

//獲得要下載文件的絕對(duì)路徑

Stringpath=session.getServletContext().getRealPath("/upload_file");

//文件的完整路徑

Stringreal_path=path+"\\"+name;

?

//設(shè)置響應(yīng)頭? 告知瀏覽器竟趾,要以附件的形式保存內(nèi)容 ? filename=瀏覽器顯示的下載文件名

response.setHeader("content-disposition","attachment;filename="+name);

?

//讀取目標(biāo)文件憔购,寫(xiě)出給客戶端

IOUtils.copy(newFileInputStream(real_path),response.getOutputStream());

?

//上一步,已經(jīng)是響應(yīng)了,所以此handler直接是void

}

十二岔帽、驗(yàn)證碼

12.1 作用

防止暴力攻擊抖拦,前端安全保障

12.2 導(dǎo)入jar

<!-- Kaptcha -->

<dependency>

????<groupId>com.github.penggle</groupId>

????<artifactId>kaptcha</artifactId>

????<version>2.3.2</version>

????<exclusions>

????????<exclusion>

????????????????<groupId>javax.servlet</groupId>

????????????????<artifactId>javax.servlet-api</artifactId>

????????</exclusion>

????</exclusions>

</dependency>

12.3 聲明驗(yàn)證碼組件

<servlet>

????<servlet-name>cap</servlet-name>

????<servlet-class>com.google.code.kaptcha.servlet.KaptchaServlet</servlet-class>

????<init-param>

????????<param-name>kaptcha.border</param-name>

????????<param-value>no</param-value>

????</init-param>

????<init-param>

????????<param-name>kaptcha.textproducer.char.length</param-name>

????????<param-value>4</param-value>

????</init-param>

????<init-param>

????????<param-name>kaptcha.textproducer.char.string</param-name>

????????<param-value>abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789</param-value>

????</init-param>

????<init-param>

????????<param-name>kaptcha.background.clear.to</param-name>

????????<param-value>211,229,237</param-value>

????</init-param>

????<init-param>

????<!-- session.setAttribute("captcha","驗(yàn)證碼") -->

????????<param-name>kaptcha.session.key</param-name>

????????<param-value>captcha</param-value>

????</init-param>

</servlet>

<servlet-mapping>

????????<servlet-name>cap</servlet-name>

????????<url-pattern>/captcha</url-pattern>

</servlet-mapping>

12.4 Page

<imgsrc="${pageContext.request.contextPath}/captcha"style="width:85px"id="cap"/>

<script>

$(function(){

$("#cap").click(function(){

//刷新驗(yàn)證碼

path=$(this).attr("src")+"?"+newDate().getTime();

$(this).attr("src",path);

? ? ?? });

?? });

</script>

十三塌计、REST

13.1 開(kāi)發(fā)風(fēng)格

是一種開(kāi)發(fā)風(fēng)格走诞,遵從此風(fēng)格開(kāi)發(fā)軟件氓辣,符合REST風(fēng)格,則RESTFUL账蓉。

兩個(gè)核心要求:

每個(gè)資源都有唯一的標(biāo)識(shí)(URL)

不同的行為,使用對(duì)應(yīng)的http-method

訪問(wèn)標(biāo)識(shí)資源

http://localhost:8989/xxx/users所有用戶

http://localhost:8989/xxx/users/1用戶1

http://localhost:8989/xxx/users/1/orders用戶1的所有訂單

請(qǐng)求方式標(biāo)識(shí)意圖

GEThttp://localhost:8989/xxx/users查詢所有用戶

POSThttp://localhost:8989/xxx/users在所有用戶中增加一個(gè)

PUThttp://localhost:8989/xxx/users在所有用戶中修改一個(gè)

DELETEhttp://localhost:8989/xxx/users/1刪除用戶1

GEThttp://localhost:8989/xxx/users/1查詢用戶1

GEThttp://localhost:8989/xxx/users/1/orders查詢用戶1的所有訂單

POSThttp://localhost:8989/xxx/users/1/orders在用戶1的所有訂單中增加一個(gè)

13.2 優(yōu)點(diǎn)

**輸出json:

13.3 使用

13.3.1 定義Rest風(fēng)格的 Controller

@RequestMapping(value="/users",method = RequestMethod.GET)

等價(jià)

@GetMapping("/users")

@RestController

publicclassRestController{

@GetMapping("/users")

publicList<User>queryAllUsers(){

????System.out.println("get");

????List<User>users=....

????return users;

?? }

?

@PostMapping("/users")

publicStringaddUser(@RequestBodyUseruser){

System.out.println("Post user :"+user);

return "{status:1}";

?? }


@PutMapping("/users")

publicStringupdateUser(@RequestBodyUseruser){

????System.out.println("Put user"user:"+user);

????return "{status:1}";

?? }

?

@GetMapping("/users/{id}")

publicStringqueryOneUser(@PathVariableIntegerid){//@PathVariable 接收路徑中的值

????System.out.println("Get user id:"+id);

????return "{status:1}";

?? }

?

@DeleteMapping("/users/{id}")

publicStringdeleteOneUser(@PathVariableIntegerid){//@PathVariable 接收路徑中的值

????System.out.println("delete user id:"+id);

????return"{status:1}";

?? }

}

13.3.2 Ajax請(qǐng)求

<script>

? ? functionputUser(){// 發(fā)送更新請(qǐng)求 (增加請(qǐng)求發(fā)送方式也是如此)

varxhr=newXMLHttpRequest();

? ? //定義 put逾一,delete,get,post方式 即可铸本,不用定義_method

xhr.open("put","${pageContext.request.contextPath}/rest04/users");

? ? // 設(shè)置請(qǐng)求頭

xhr.setRequestHeader("content-type","application/json");

// 設(shè)置請(qǐng)求參數(shù)

varuser={id:1遵堵,NAME:"shine"箱玷,city:"bj","birth":"2020/12/12"陌宿,"salary":100.5};

xhr.send(JSON.stringify(user));

xhr.onreadystatechange=function(){

if(xhr.readyState==4&&xhr.status==200){

varret=xhr.responseText;

// 解析json锡足,并輸出

console.log(JSON.parse(ret));

? ? ? ? ?? }

? ? ?? }

? ? /*$.ajax({

? ? ? ? ?? url:'${pageContext.request.contextPath}/rest04/users',

? ? ? ? ?? type:'put',

? ? ? ? ?? contentType:"application/json",//聲明請(qǐng)求參數(shù)類型為 json

? ? ? ? ?? data:JSON.stringify(user),// 轉(zhuǎn)換js對(duì)象成json

? ? ? ? ?? success:function(ret){

? ? ? ? ? ? ?? console.log(JSON.parse(ret));

? ? ? ? ?? }

? ? ?? });*/

?? }

?

? ? functiondelUser(){// 發(fā)送刪除請(qǐng)求

varxhr=newXMLHttpRequest();

//定義 put,delete,get,post方式 即可壳坪,不用定義_method

xhr.open("delete","${pageContext.request.contextPath}/rest04/users/1");

xhr.send();

xhr.onreadystatechange=function(){

if(xhr.readyState==4&&xhr.status==200){

varret=xhr.responseText;

console.log(JSON.parse(ret));

? ? ? ? ?? }

? ? ?? }

?? }

</script>

十四舶得、跨域請(qǐng)求

14.1 域

域:協(xié)議+IP+端口

http://localhost:8989

http://localhost:8080

http://www.baidu.com:80

14.2 Ajax跨域問(wèn)題

Ajax發(fā)送請(qǐng)求時(shí),不允許跨域爽蝴,以防用戶信息泄露沐批。

當(dāng)Ajax跨域請(qǐng)求時(shí),響應(yīng)會(huì)被瀏覽器攔截(同源策略)蝎亚,并報(bào)錯(cuò)九孩。即瀏覽器默認(rèn)不允許ajax跨域得到響應(yīng)內(nèi)容。

互相信任的域之間如果需要ajax訪問(wèn)发框,(比如前后端分離項(xiàng)目中躺彬,前端項(xiàng)目和后端項(xiàng)目之間),則需要額外的設(shè)置才可正常請(qǐng)求。

14.3 解決方案

允許其他域訪問(wèn)

在被訪問(wèn)方的Controller類上宪拥,添加注解

@CrossOrigin("http://localhost:8080")//允許此域發(fā)請(qǐng)求訪問(wèn)

publicclassSysUserController{

? ? ....

}

攜帶對(duì)方cookie仿野,使得session可用

在訪問(wèn)方,ajax中添加屬性:withCredentials: true

$.ajax({

type:"POST",

url:"http://localhost:8989/web/sys/login",

...,

xhrFields: {

// 跨域攜帶cookie

withCredentials:true

? ? }

});

varxhr=newXMLHttpRequest();

// 跨域攜帶cookie

xhr.withCredentials=true;

十五江解、SpringMVC執(zhí)行流程


十六设预、Spring整合

16.1 整合思路

此時(shí)項(xiàng)目中有兩個(gè)工廠

DispatcherServlet 啟動(dòng)的springMVC工廠==負(fù)責(zé)生產(chǎn)C及springMVC自己的系統(tǒng)組件

ContextLoaderListener 啟動(dòng)的spring工廠==負(fù)責(zé)生產(chǎn)其他所有組件

springMVC的工廠會(huì)被設(shè)置為spring工廠的子工廠,可以隨意獲取spring工廠中的組件

整合過(guò)程犁河,就是累加:代碼+依賴+配置鳖枕。然后將service注入給controller即可

16.2 整合技巧

兩個(gè)工廠不能有彼此侵入,即桨螺,生產(chǎn)的組件不能有重合宾符。

<!-- 告知SpringMVC? 哪些包中 存在 被注解的類

? ? use-default-filters=true 凡是被 @Controller @Service? @Repository注解的類,都會(huì)被掃描

? ? use-default-filters=false 默認(rèn)不掃描包內(nèi)的任何類, 只掃描include-filter中指定的類

? ? 只掃描被@Controller注解的類

-->

<context:component-scanbase-package="com.zhj"use-default-filters="false">

? <context:include-filtertype="annotation"expression="org.springframework.stereotype.Controller"/>

</context:component-scan>

<!-- 告知Spring 唯獨(dú)不掃描@Controller注解的類 -->

<context:component-scanbase-package="com.zhj"use-default-filters="true">

? ? <context:exclude-filtertype="annotation"expression="org.springframework.stereotype.Controller"/>

</context:component-scan>

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末灭翔,一起剝皮案震驚了整個(gè)濱河市魏烫,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌肝箱,老刑警劉巖哄褒,帶你破解...
    沈念sama閱讀 221,430評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異煌张,居然都是意外死亡呐赡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,406評(píng)論 3 398
  • 文/潘曉璐 我一進(jìn)店門骏融,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)链嘀,“玉大人,你說(shuō)我怎么就攤上這事档玻』巢矗” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 167,834評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵误趴,是天一觀的道長(zhǎng)霹琼。 經(jīng)常有香客問(wèn)我,道長(zhǎng)凉当,這世上最難降的妖魔是什么碧囊? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 59,543評(píng)論 1 296
  • 正文 為了忘掉前任,我火速辦了婚禮纤怒,結(jié)果婚禮上糯而,老公的妹妹穿的比我還像新娘。我一直安慰自己泊窘,他們只是感情好熄驼,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,547評(píng)論 6 397
  • 文/花漫 我一把揭開(kāi)白布像寒。 她就那樣靜靜地躺著,像睡著了一般瓜贾。 火紅的嫁衣襯著肌膚如雪诺祸。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 52,196評(píng)論 1 308
  • 那天祭芦,我揣著相機(jī)與錄音筷笨,去河邊找鬼。 笑死龟劲,一個(gè)胖子當(dāng)著我的面吹牛胃夏,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播昌跌,決...
    沈念sama閱讀 40,776評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼仰禀,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了蚕愤?” 一聲冷哼從身側(cè)響起答恶,我...
    開(kāi)封第一講書(shū)人閱讀 39,671評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎萍诱,沒(méi)想到半個(gè)月后悬嗓,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,221評(píng)論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡裕坊,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,303評(píng)論 3 340
  • 正文 我和宋清朗相戀三年包竹,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片碍庵。...
    茶點(diǎn)故事閱讀 40,444評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖悟狱,靈堂內(nèi)的尸體忽然破棺而出静浴,到底是詐尸還是另有隱情,我是刑警寧澤挤渐,帶...
    沈念sama閱讀 36,134評(píng)論 5 350
  • 正文 年R本政府宣布苹享,位于F島的核電站,受9級(jí)特大地震影響浴麻,放射性物質(zhì)發(fā)生泄漏得问。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,810評(píng)論 3 333
  • 文/蒙蒙 一软免、第九天 我趴在偏房一處隱蔽的房頂上張望宫纬。 院中可真熱鬧,春花似錦膏萧、人聲如沸漓骚。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,285評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)蝌蹂。三九已至噩斟,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間孤个,已是汗流浹背剃允。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,399評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留齐鲤,地道東北人斥废。 一個(gè)月前我還...
    沈念sama閱讀 48,837評(píng)論 3 376
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像佳遂,于是被迫代替她去往敵國(guó)和親营袜。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,455評(píng)論 2 359