1. 程式人生 > 遊戲 >新一批國產遊戲版號下發 《漫威對決》《全境封鎖2》過審

新一批國產遊戲版號下發 《漫威對決》《全境封鎖2》過審

//springmvc就是一個spring框架,它能建立物件,並將物件放到springMVC的容器中。也能使用ioc管理物件,也可以使用<bean>,@Component,@Repository,@Service,@Controller等註解。但springmvc容器中主要放的是控制器物件

一、控制器物件

//使用@Controller註解建立控制器物件,用該物件接收使用者的請求,顯示處理結果,可以看作成一個Servlet使用

//但使用@Controller註解建立的物件是一個普通物件,能將其看成一個Servlet,但其本質上不是一個Servlet,因為該物件沒有繼承HttpServlet類,它不能直接接收使用者有瀏覽器傳送過來的請求,只能就受中央排程器的二次轉發

//在springmvc中有一個servlet:DispatcherServlet(中央排程器)它負責直接接收使用者的請求,再將請求轉發給控制器物件,對請求進行處理

二、第一個例子

  1. 在web.xml檔案中對DispatcherServlect物件進行註冊

<servlet>
<servlet-name>aaa</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name> //contextConfigLocation固定寫法
<param-value>classpath:springmvc.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
<servlet-name>aaa</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>

//DispatcherServlet物件需要在伺服器啟動時被建立,因為該物件被建立的同時,也同時會建立springmvc的容器物件,並讀取springmvc的配置檔案,將springmvc配置檔案中的物件都建立好,當用戶發起請求時,可直接使用物件,節約時間。所以得加入<load-on-startup>標籤

//DispatcherServlet物件被建立後,會執行初始化方法init(),init()的內容是

  1. 建立容器,讀取配置檔案:WebApplicationContext ctx=new ClassPathXmlApplicationContext ("springmvc.xml")

  2. 把容器物件放到ServletContext中:getServletContext().setAttribute(key,ctx)

//<init-param>標籤中是配置Tomcat伺服器讀取springmvc.xml配置檔案的位置,以上配置是在類路徑的根目錄下讀取;預設位置是:/WEB-INF/<servlet-name>-servlet.xml,<servlet-name>在這裡是aaa

//<load-on-startup>標籤要寫在<init-param>標籤後面,不然會報錯

  1. 建立控制類

@Controller
public class MyController {
@RequestMapping("/some.do")
public ModelAndView doSome(){
ModelAndView mv=new ModelAndView();
mv.addObject("a","123");
mv.addObject("b","456");
mv.setViewName("/show.jsp");
return mv;
}
}

//@Controller:定義控制器類,接收處理使用者的請求。一個控制器類中可以有多個處理器方法

//@RequestMapping:請求對映,將一個請求地址和一個方法繫結在一起

//屬性:value,String型別,表請求的URL地址,唯一值

//位置:在方法上(常用);也可以在類上

//ModelAndView:springmvc中的一個類,表示既可以返回資料,也可以返回檢視,如:jsp等

//setViewName()方法相當於forward操作

  1. 在springmvc.xml檔案中宣告元件掃描器

<context:component-scan base-package="com.dh.controller"/>

//base-package:控制器類所在的包名

三、springmvc請求處理過程

  1. 發起請求:.../some.do

  2. Tomcat接收到請求後,解析出其uri,然後找到對應的<url-pattern>為*.do的Servlet——DispatcherServlet

  3. DispatcherServlet通過springmvc配置檔案掃描控制器包,找到@Controller註解類,找到對應的處理器方法

  4. DispatcherServlet把.../some.do請求轉發給doSome()方法

  5. 框架執行doSome方法,把得到的ModelAndView進行處理,轉發到show.jsp中

四、檢視解析器

//當show.jsp在webapp的根目錄下是,使用者是可以直接通過網址訪問的

//我們可以將show.jsp放在WEB-INF目錄下,該目錄下的檔案是受保護的,無法直接由網頁地址訪問

//setViewName()方法中的路徑改為

 mv.setViewName("/WEB-INF/show.jsp");

//配置檢視解析器在springmvc.xml之中

<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/"/> //字首:檢視檔案路徑
<property name="suffix" value=".jsp"/> //字尾:檢視副檔名
</bean>

//setViewName()方法中的路徑改為

 mv.setViewName("show");

五、@RequestMapping註解

在類上

@Controller
@RequestMapping("test")
public class MyController {
@RequestMapping("/some.do")
public ModelAndView doSome(){

//此時doSome()方法的真實url為:/test/some.do

//test出現在類上,被所有的處理其方法共有,所以被稱為模組名稱

Method屬性

public class MyController {
@RequestMapping(value = "/some.do",method = RequestMethod.GET)
public ModelAndView doSome(){
}

//method屬性:表示接收請求方式,它的值是RequestMethod列舉值。常用的有GET,POST,PUT......

//若method=RequestMethod.GET,此時傳送post請求,則報錯:405

//若在@RequestMapping註解中不指定method屬性,則該方法可以接收任何請求方式的請求,沒有限制

六、處理器方法的引數

四類引數

  1. HttpServletRequest

  2. HttpServletResponse

  3. HttpSession

  4. 使用者提交的引數(逐個接收,物件接收)

//前3種引數可以直接使用,在呼叫時由系統自動賦值

@RequestMapping(...)
public ModelAndView doSome(HttpServletRequest request, HttpServletResponse response, HttpSession session){
request...
session...
}

逐個接收

//適合引數數量較少時使用

<form action="receive.do" method="post">
姓名:<input type="text" name="name"/> <br> //abc
年齡:<input type="text" name="age"/> <br> //123
<input type="submit" value="提交">
</form>
@RequestMapping(value = "receive.do",method = RequestMethod.POST)
public ModelAndView doSome(String name,int age){ //這裡int使用的自動型別轉換
System.out.println(name);
System.out.println(age); //abc 123
return mv;
}

//處理器方法的形參名必須和請求中的引數名一致。系統自動會將同名的請求引數賦給同名的形參,不關心位置,只看名稱

//底層是String age=request.getParameter("age"),然後框架提供了自動轉換功能,能將String轉換為int,float等型別

//若年齡一欄不寫,空著提交。則網頁:400;控制檯:不會拋異常,但會出現在伺服器日誌上。原因是空串無法轉化為int型別。解決辦法:doSome(String name,integer age),這樣空串就轉化為null,就不會報錯了(實驗證明:沒啥用,依然會報錯400:Required Integer parameter 'age' is not present)。若年齡一欄填12.9或abc這樣的,依然報錯

中文亂碼問題

//在提交請求引數時,get請求中沒有中文亂碼,使用post請求提交請求時,中文有亂碼問題,需使用過濾器處理亂碼

//過濾器可以自定義,也可以使用springmvc提供的過濾器:CharacterEncodingFilter

//在web.xml中新增

<filter>
<filter-name>abc</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>forceRequestEncoding</param-name>
<param-value>true</param-value> //強制HttpServletRequest物件使用上面encoding中的編碼方式
</init-param>
<init-param>
<param-name>foreResponseEncoding</param-name>
<param-value>true</param-value> //強制HttpServletResponse物件使用上面encoding中的編碼方式
</init-param>
</filter>
<filter-mapping>
<filter-name>abc</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

//forceRequestEncoding,foreResponseEncoding的預設值都是false

@RequestParam註解

//在逐個接收請求中,解決請求中的引數名與處理器方法的形參名不一樣的問題

//位置:在處理器方法的形參前面

//屬性:value:請求中的引數名稱

required:boolean型別,預設值為true。為true時,表示請求中必須包含該引數,即使在文字框中什麼都不寫,該引數的值為空串,依然會提交上來,不會報錯。它其實指的是哪些沒有name屬性,無法提交的引數,若又設定了它的required值為true,就會報錯:400。若不寫required屬性,預設為true

@RequestMapping(value = "receive.do",method = RequestMethod.POST)
public ModelAndView doSome(@RequestParam(value = "name",required = false) String a,
@RequestParam(value = "age") Integer b){
System.out.println(a);
System.out.println(b);
}

物件接收資料

//適合引數數量較多時使用

public class Student {
private String name;
private Integer age; //還要寫構造,set,get等方法
...
}

@Controller
public class MyController {
@RequestMapping(value = "other.do",method = RequestMethod.POST)
public ModelAndView doother(Student stu){
System.out.println(stu.getName());
System.out.println(stu.getAge());
}
}

//Studnet類中的屬性名必須和請求中的引數名相同

//在doother(Student stu)中,框架會自動將請求中的引數賦給同名的屬性,完成stu物件的賦值

//doother(物件1,物件2,物件3,...):可同時有多個物件

七、處理器方法的返回值

ModelAndView資料+檢視
String 檢視,不能返回資料
void 即不返回資料,又不能跳轉到其他的檢視
物件Object 返回資料,但不能跳轉到其他檢視

String

@Controller
public class ReturnController {
@RequestMapping(value = "string.do",method = RequestMethod.POST)
public String doString(String name, Integer age) {
System.out.println(name);
System.out.println(age); //abc 12
return "show";
}
}

//使用該返回值,依然能接受表單提交的資料,但無法將表單的資料輸出到show.jsp中

// return "show";語句就相當於forward,跳轉到show.jsp檔案,但由於其無法攜帶資料,所以此時的show.jsp是一個靜態頁面

//若想攜帶資料跳轉,則doString(HttpServletRequest request,String name, Integer age)——request.setAttribute("a",name),加入引數request,將資料裝進request域中,再在jsp檔案中通過El表示式獲取

//假設show.jsp檔案在WEB-INF目錄下,當有檢視解析器時,只需返回邏輯名稱即可:return "show"; 當沒有檢視解析器時,就需要返回完整檢視路徑:return "WEB-INF/show.jsp";

void

@RequestMapping(value="void.do",method = RequestMethod.POST)
public void doVoid(String name, Integer age) {
System.out.println(name);
System.out.println(age);
PrintWriter out=response.getWriter();
Student s=new Student();
s.setName("ww");
s.setAge(66);
out.print(s);
out.flush();
out.close();
}

//因為沒有返回值,所以不能跳轉到其他頁面。但在處理Ajax時,通過新增 HttpServletResponse response引數輸出資料,響應Ajax請求。注:要加入Jackson依賴

Object

//若處理器方法的返回值是Object型別,則該處理器方法必須有@ResponseBody註解,否則無法訪問該處理器方法

  1. 在springmvc.xml加入註解驅動

<context:component-scan base-package="com.dh.Controller"/>

<mvc:annotation-driven/>

//註解驅動的作用是:完成java物件到json,xml,text,二進位制等資料格式的轉化

//其底層是通過HttpMessageConveter介面(訊息轉化器)實現的。該介面有很多實現類,完成資料的轉化,我們需要記住的是:

StringHttpMessageConverter        //轉為字串格式
MappingJackson2HttpMessageConverter //轉為接送格式

//該介面有5個方法:以下兩個是控制器類把結果輸出給瀏覽器時使用的

boolean canWrite(Class<?> var1, @Nullable MediaType var2);
void write(T var1, @Nullable MediaType var2, HttpOutputMessage var3)

//canWrite方法是檢查處理器方法的返回值能不能轉化為var2表示的資料格式。若能,返回true;MediaType是資料格式封裝的類,如json,xml等

//write方法是呼叫Jackson中的ObjectMapper方法將處理器方法的返回值物件轉化為json格式

  1. @ResponseBody註解

@Controller
public class MyController {
@ResponseBody
@RequestMapping("some.do")
public Student doSome(String name,Integer age) {
System.out.println(name);
System.out.println(age);
Student s=new Student();
s.setName("ww");
s.setAge(66);
return s;
}
}

//@ResponseBody註解是放在處理器方法上。底層是通過HttpServletResponse輸出資料,響應Ajax的請求

PrintWriter out=response.getWriter();
out.print(s);
out.flush();
out.close(); //@ResponseBody註解代替的程式碼

//若處理器方法的返回值是Object型別,則該處理器方法必須有@ResponseBody註解,否則無法訪問該處理器方法

//@ResponseBody註解是無法用於其他的返回值型別,比如:void,ModelAndView等

//返回物件的處理過程

  • 框架會先呼叫HttpMessageConveter介面中的每個實現類的canWrite方法,檢查那個實現類能處理Student型別的資料。在這裡選擇的是:MappingJackson2HttpMessageConverter,轉為json

  • 之後呼叫MappingJackson2HttpMessageConverter實現類的write方法,把Student的物件轉化為json格式,底層是Jackson中的ObjectMapper方法。並且規定了字符集utf-8

  • 最後呼叫@ResponseBody註解,將轉化後的資料輸出到瀏覽器中,完成Ajax的請求

Sting與Object的String區別

@ResponseBody
@RequestMapping(value = "string.do",produces = "text/plain;charset=utf-8")
public String doString(String name,Integer age) {
System.out.println("String:"+name);
System.out.println("String:"+age);
return "Hello,張三";
}

//前面的Sring是返回檢視,這裡的String是返回的資料——String物件,屬於Object中的。區分兩者就是看有沒有@ResponseBody註解

//produces = "text/plain;charset=utf-8"語句是解決輸出資料的中文字元亂碼問題的;若Ajax是使用jQuery寫的,解決中文亂碼和String型別無法轉化為json問題,請看筆記P39頁

八、靜態資源處理

//springmvc框架中中央排程器DispatcherServlet的<url-pattern>有兩種值

(1) *.xxx

(2) / (只是單獨一個斜槓,後面不能跟其他東西)

//斜槓是專門處理未對映到其他Servlet的請求。AServlet的url-pattern為/a,BServlet的url-pattern為/b,此時在網頁上訪問http://localhost:8080/c,由於/c沒有 與其對應的Servlet,所以就屬於未對映的到其他的Servlet請求。這種請求主要包含靜態資源,如:html,圖片,js等檔案都屬於

//Tomcat伺服器中有一個內建的Servlet:org.apache.catalina.servlets.DefaultServlet,專門是用來處理靜態資源的

處理靜態資源方式1

  1. 將中央排程器DispatcherServlet的<url-pattern>改為/,不用額外增加另外的為*.do的<url-pattern>也能訪問some.do為url的Servlet,或者相關的控制器類。

  2. 中央排程器DispatcherServlet的<url-pattern>改為/後,導致DispatcherServlet替代了org.apache.catalina.servlets.DefaultServlet的作用。但DispatcherServlet沒有處理靜態資源的能力,因為沒有對應的控制器物件。所靜態資源訪問都是404。但不影響some.do這類的請求

  3. 所以在加入springmvc.xml中加入以下標籤來處理靜態資源

<mvc:default-servlet-handler/>

//加入該標籤後,框架會自動建立DefaultServletHttpRequestHandler控制物件,該物件的作用就是將所有請求轉發給tomcat的org.apache.catalina.servlets.DefaultServlet,讓他來處理靜態資源

  1. 但該標籤與@RequestMapping註解有衝突,靜態資源可以正常訪問,但some.do不行。原因可能是DefaultServletHttpRequestHandler把所有請求都轉給Tomcat處理了,而org.apache.catalina.servlets.DefaultServlet不能處理控制器物件相關的請求,由轉不出來,所以就不能訪問。所以需要在springmvc.xml中加入註解驅動

<mvc:annotation-driven/>

//該方式的優點:簡單,方便;缺點:必須依賴伺服器,而且該伺服器必須有org.apache.catalina.servlets.DefaultServlet才行

處理靜態資源方式2(常用)

//假設有a.html檔案在webapp/html/目錄下,則在springmvc.xml中新增

<mvc:resources mapping="/html/**" location="/html/"/>

//mapping:訪問靜態資源的url地址,可以使用萬用字元:**

//location:靜態資源在你專案中的目錄位置

//<mvc:resources>標籤:該標籤加入springmvc.xml中後,會建立ResourceHttpRequestHandler處理器應用,它是springmvc內建的,專門用來處理靜態資源的。之後就不需要依賴其他伺服器,在框架內部即可完成

//<mvc:resources>標籤與@RequestMapping註解有一定的衝突,所以需要加入註解驅動

<mvc:annotation-driven/>

絕對路徑獲取

<%
String basePath=request.getScheme()+"://"+
request.getServerName()+":"+
request.getServerPort()+
request.getContextPath()+"/"; //basePath表示的網址:http://localhost:8080/myweb/

%>
<base href="basePath"/>
<a href="/some.do">跳轉</a> //這裡的真實href為:http://localhost:8080/myweb/some.do,簡寫了

//加上<base href="basePath"/>後,以下所有標籤中的url都有這個字首:http://localhost:8080/myweb/,相當於簡寫了

九、SSM整合開發

//整合開發以註解方式為主,xml配置檔案為輔

整合中的容器

  1. springmvc容器:管理Controller控制器物件

  2. spring容器:管理Servlet,Dao。工具類物件

//兩個容器都是獨立存在的;springmvc容器是spring容器的子容器,類似java中的繼承關係:子可以訪問父的內容。在子容器中的Controller控制器物件可以訪問父容器中的Service物件。

解決Controller到資料庫的亂碼


jdbc.url=jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=UTF-8

//新增 ?useUnicode=true&characterEncoding=UTF-8 這一段是解決從service寫入資料庫中,造成資料的中文亂碼問題,但不能使資料庫中已經亂碼的資料復原回來,只作用於新加入的資料

十、重定向與轉發

  1. 請求轉發

mv.setViewName("forward:檢視檔案的完整路徑")

//添加了forward與沒新增forward,沒有區別,setViewName方法本身就是forward方式

//forward特點:不和檢視解析器一起使用,即使專案中有檢視解析器,也當其沒有。forward後依然要跟完成路徑

//forward後的完成路徑以webapp的根目錄為起點開始算的

//forward底層是request.getRequestDispatcher ("xxx.jsp") .forward ()

  1. 重定向

mv.setViewName("redirect:檢視檔案的完整路徑")

//兩次請求,第二次的請求(即重定向的那次)不能訪問WEB-INF中的資源

//redirect特點:不和檢視解析器一起使用,即使專案中有檢視解析器,也當其沒有。redirect後依然要跟完成路徑

//redirect底層是response.sendRedirect ("xxx.jsp")

十一、異常處理

//springmvc框架採用的是統一,全域性的異常處理。把controller中所有的異常處理都集中到一個地方(這樣就不用在每個地方中寫try..catch,單獨處理),把異常處理和業務邏輯程式碼分開,解耦合

//採用了aop思想,增強目標類的功能

異常處理步驟

  1. 在控制器類的處理器方法中丟擲異常InsertFailException(自定義的異常)

  2. 建立普通類作為全域性異常處理類

package com.dh.handler;

@ControllerAdvice
public class handler {

@ExceptionHandler(InsertFailException.class)
public ModelAndView doInsertFailException(Exception ex){
ModelAndView mv = new ModelAndView();
mv.addObject("ex",ex);
mv.setViewName("doException"); //跳轉到異常處理頁面
return mv;
}
}

//@ControllerAdvice:控制器增強(即給控制器類增加了異常處理功能);位置:在類上

//@ExceptionHandler:定義異常處理方法。異常處理方法與處理方法一樣,有4中返回值型別,即String,ModelAndView,viod,object;異常處理方法的形參為Exception,可列印指定異常的異常資訊

//@ExceptionHandler的屬性是value,值為異常類。當控制器類中的方法丟擲指定異常時,轉到對應的異常處理方法,執行該異常方法中的內容,不會再回到原控制器類中的方法

//同一個異常處理類中可有多個異常處理方法;若還有一個異常處理方法,但該方法沒有指定value值,則該異常處理方法處理除了InsertFailException異常外的所有異常

  1. 為異常處理類所在包配置元件掃描器

<context:component-scan base-package="com.dh.handler"/>

異常處理邏輯

  1. 需要把異常記錄下來,記錄到資料庫中,以及日誌檔案。記錄日誌發生的時間,位置,異常錯誤內容

  2. 傳送通知,把異常資訊通過郵件,簡訊等方式傳送給相關人員

  3. 給使用者友好的提示,不要404頁面

十二、攔截器

  1. 攔截器是springmvc框架中的,需要實現HandlerInterceptor介面

  2. 攔截器與過濾器類似,但功能的側重點不同。過濾器主要是用來過濾請求引數的,設定字元編碼等工作;攔截器是攔截使用者請求的,做請求的判斷處理

  3. 攔截器是全域性的,可以同時對多個Controller做攔截。一個專案中可以有多個攔截器,它們同時起作用

HandlerInterceptor中方法

預處理方法

public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)

//引數Object handler為被攔截的控制器物件

//該方法在控制器類中的處理器方法執行之前執行;該方法可以驗證使用者資訊是否符合,驗證失敗,返回false,截斷請求

後處理方法

public void postHandle(HttpServletRequest request, 
HttpServletResponse response,
Object handler,
ModelAndView modelAndView)

//該方法在處理器方法之後執行

//通過引數ModelAndView modelAndView可獲取處理器方法的返回值,再在後處理方法中對檢視,資料進行二次修改,可以影響最後的輸出結果

最後執行的方法

public void afterCompletion(HttpServletRequest request,
HttpServletResponse response,
Object handler,
Exception ex)

//在請求處理完成後執行,即當處理器方法中的跳轉到指定檢視中的語句執行之後,就認為該請求處理完成

//該方法一般做資源回收工作,即刪除一些建立的物件,回收佔有的記憶體

多個攔截器的執行順序

//框架中的攔截器按照宣告的先後順序放到ArrayList集合中,越先宣告,該攔截器就越先執行

//若有a,b兩個攔截器,a先宣告

1. a.preHandler()
2. b.preHandler()
3. MyController.doSome()
4. b.postHandler()
5. a.postHandler()
6. b.afterCompletion()
7. a.afterCompletion()

//若a,b的preHandler()都返回true,則按上述順序執行

//若a.preHandler()返回true,b.preHandler()返回false,則只會執行1,2,7三個方法

//若a.b的preHandler()都返回false,則只執行1方法

//無論有多少個攔截器,只要其中一個攔截器的preHandler()方法返回false,則不會執行控制器類的處理器方法

攔截器與過濾器的區別

  1. 過濾器是Servlet中的物件,攔截器是springmvc框架中

  2. 過濾器是實現Filter介面,攔截器是實現HandlerInterceptor介面

  3. 過濾器主要是用來設定request,response引數的屬性的,側重資料過濾;攔截器主要是用來驗證請求,截斷請求的

  4. 過濾器在攔截器之前執行

  5. 過濾器只有一個執行時間點,攔截器有3個

  6. 過濾器可以處理jsp,html等靜態資源;攔截器側重攔截Controller物件,若你的請求不能被DispatcherServlet接收,則該請求不會受到攔截器的攔截

  7. 攔截器攔截普通方法執行,過濾器是過濾Servlet請求

  8. 過濾器是Tomcat伺服器建立物件,攔截器是spring容器中建立物件