springMVC
SpringMVC分為:
前端控制器:當(dāng)用戶請(qǐng)求時(shí)綜合調(diào)用映射器咐刨、適配器插龄、控制器上遥、視圖解析器對(duì)用戶的請(qǐng)求進(jìn)行響應(yīng)
映射器:對(duì)前端控制器發(fā)送的URL路徑進(jìn)行檢查澡谭,如果路徑錯(cuò)誤返回404
適配器:尋找正確的控制器纯命,如果找不到拋出異常
控制器:對(duì)用戶的請(qǐng)求進(jìn)行處理西剥,將請(qǐng)求得到的數(shù)據(jù)以及要顯示的視圖放入ModelAndView對(duì)象中
視圖解析器:接收ModelAndView對(duì)象,從中獲取數(shù)據(jù)亿汞,經(jīng)過處理組合成視圖交給前端控制器進(jìn)行處理
DispatcherServlet原理
1瞭空、根據(jù)請(qǐng)求的路徑找到HandlerMethod(帶有Method反射屬性,也就是對(duì)應(yīng)Controller中的方法)
2疗我、然后匹配路徑對(duì)應(yīng)的攔截器
3咆畏、通過HandlerMapping接口實(shí)現(xiàn)類獲得HandlerExecutionChain對(duì)象(包含HandlerMethod和攔截器)
4、有了HandlerExecutionChain之后吴裤,通過HandlerAdapter對(duì)象進(jìn)行處理得到ModelAndView對(duì)象
調(diào)用HandlerMethod內(nèi)部handle的時(shí)候:
1旧找、使用各種HandlerMethodArgumentResolver接口實(shí)現(xiàn)類,完成參數(shù)綁定
2麦牺、使用到各種Converter接口實(shí)現(xiàn)類钮蛛,完成類型轉(zhuǎn)換
3、使用各種HandlerMethodReturnValueHandler接口實(shí)現(xiàn)類枕面,處理返回值
4愿卒、最終返回值被處理成ModelAndView對(duì)象
5、這期間發(fā)生的異常會(huì)被HandlerExceptionResolver接口實(shí)現(xiàn)類進(jìn)行處理
5潮秘、RequestToViewNameTranslator接口實(shí)現(xiàn)類將請(qǐng)求地址解析為視圖名(若有手動(dòng)設(shè)置視圖名琼开,則使用手動(dòng)設(shè)置的)
6、通過各種View和ViewResolver接口實(shí)現(xiàn)類渲染視圖(將Model中的數(shù)據(jù)放到request域?qū)ο笾姓碥瘢?yè)面的編譯柜候。。躏精。)
前端控制器
前端控制器在web.xml中配置
<servlet>
<!-- 命名 -->
<servlet-name>springmvc</servlet-name>
<!-- 加載包中的前端控制器 -->
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- 讓服務(wù)器已啟動(dòng)就開始加載文件springMVC.xml渣刷,用的是contextConfigLocation這個(gè)屬性 -->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springMVC.xml</param-value>
</init-param>
<!-- 啟動(dòng)加載 -->
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<!-- 對(duì)應(yīng)上面的命名 -->
<servlet-name>springmvc</servlet-name>
<!-- 對(duì)文件進(jìn)行攔截來執(zhí)行上面的程序, "/"代表攔截所有的-->
<url-pattern>/</url-pattern>
</servlet-mapping>
兩種映射器
<!-- 映射器 -->
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"></bean>
<!-- 映射器2 -->
<bean class=" org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="mappings">
<props>
<!-- 這里的值要和控制器中的id相對(duì)應(yīng) -->
<prop key="/text1">text</prop>
<prop key="/text1">text</prop>
</props>
</property>
</bean>
兩種適配器
<!-- 適配器 要實(shí)現(xiàn)Controller接口-->
<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"></bean>
<!-- 適配器2 要實(shí)現(xiàn) HttpRequestHandler接口 -->
<bean class=" org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter"></bean>
控制器
<!-- 控制器 -->
<bean class="com.hemi.controller.MyController" name="/text" id="text"></bean>
后端控制器代碼
public class MyController implements org.springframework.web.servlet.mvc.Controller{
@Override
public ModelAndView handleRequest(HttpServletRequest req, HttpServletResponse resp) throws Exception {
String username = req.getParameter("username");
String password = req.getParameter("password");
// req.setAttribute("username", username);
// req.setAttribute("password", password);
ModelAndView view = new ModelAndView();
if("lisi".equals(username)&&"123".equals(password)){
view.setViewName("Hello.jsp");
}
else{
view.setViewName("login.jsp");
}
return view;
}
}
視圖解析器
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"></bean>
視圖解析器的配置前綴后綴
<!-- 視圖解析器 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!-- 前綴 -->
<property name="prefix" value="/"></property>
<!-- 后綴 -->
<property name="suffix" value=".jsp"></property>
</bean>
使用注解的方式配置springMVC
注意:注解適配器和映射器要一起使用才有效
注解適配器和映射器要一起使用才有效
<!-- 掃描包 -->
<context:component-scan base-package="com.hemi.controller"></context:component-scan>
<!-- 配置注解 1-->
<!-- 配置映射器注解 -->
<bean class=" org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping "></bean>
<!-- 配置適配器注解 -->
<bean class=" org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"></bean>
<!--配置注解2-->
<!-- 終極替換上面的注解 -->
<mvc:annotation-driven></mvc:annotation-driven>
- @RequestMapping("path"):在方法上使用該注解矗烛,配置對(duì)應(yīng)的映射路徑
@Controller
public class TextControler{
@RequestMapping("show1")
public ModelAndView show1(){}
}
springMVC后端控制器進(jìn)行響應(yīng)的三種方式
ModleAndView類型返回值:
view.setViewName("Hello"); 保存要顯示的視圖
view.addObject("password", password); 向域?qū)ο笾斜4鏀?shù)據(jù)(實(shí)際是保存到request域?qū)ο笾?
@RequestMapping("show1")
public ModelAndView show1(HttpServletRequest req){
String username = req.getParameter("username");
String password = req.getParameter("password");
ModelAndView view = new ModelAndView();
view.addObject("username", username);
view.addObject("password", password);
view.setViewName("Hello");
return view;
}
@RequestMapping("show1")
public ModelAndView show1(HttpServletRequest req){
String username = req.getParameter("username");
String password = req.getParameter("password");
ModelAndView view = new ModelAndView();
view.addObject("username", username);
view.addObject("password", password);
view.setViewName("Hello");
return view;
}
- String類型返回值返回視圖位置辅柴,使用Modle以及ModleMap來保存數(shù)據(jù)
@RequestMapping("show2")
public String show2(Model model,HttpServletRequest req){
String username = req.getParameter("username");
String password = req.getParameter("password");
model.addAttribute("username", username);
model.addAttribute("password", password);
return "Hello";
}
void類型返回值要用域?qū)ο髞肀4鏀?shù)據(jù),通過請(qǐng)求轉(zhuǎn)發(fā)和重定向來進(jìn)行響應(yīng)
@RequestMapping("show3")
public void show3(HttpServletRequest req,HttpServletResponse resp){
String username = req.getParameter("username");
String password = req.getParameter("password");
req.setAttribute("username", username);
req.setAttribute("password", password);
try {
req.getRequestDispatcher("Hello.jsp").forward(req, resp);
} catch (ServletException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
參數(shù)綁定
簡(jiǎn)單參數(shù)綁定:傳入的數(shù)據(jù)是以key/value的形式進(jìn)行傳遞,key和后端控制器的形參名字相同,可以使用注解@RequestParam("username")為后端控制器的形參名起別名碌嘀,與key相對(duì)應(yīng)
Pojo參數(shù)綁定:傳入的數(shù)據(jù)是以key/value的形式進(jìn)行傳遞涣旨,key值與Pojo中的屬性名稱相同
自定義類型: 進(jìn)行date和數(shù)據(jù)類型的綁定,需要自己編寫轉(zhuǎn)換類
自定義轉(zhuǎn)換類型配置步驟:
- 編寫轉(zhuǎn)換類
public class DateConvert implements Converter<String, Date>{
@Override
public Date convert(String source) {
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
try {
return format.parse(source);
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
}
- 在spring配置文件中進(jìn)行配置
<mvc:annotation-driven conversion-service="conversionService">
</mvc:annotation-driven>
<bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
<property name="converters">
<list>
<bean class="com.hemi.controller.convert.DateConvert"></bean>
</list>
</property>
</bean>
- 在實(shí)體類中對(duì)綁定的Date屬性值進(jìn)行綁定
private String username;
private String password;
@DateTimeFormat(pattern="yyyy-MM-dd")
private Date date;
- 配置后端控制器
@RequestMapping("show4")
public String show4(Model model,User user){
model.addAttribute("user", user);
return "Hello";
}
參數(shù)綁定數(shù)組(數(shù)組和list集合一樣)
前端頁(yè)面
<form action="show5" method="post">
用戶名:<input type="text" name="username"><br>
密碼:<input type="password" name="password"> <br>
日期<input type="text" name="date"><br>
<!--傳遞list集合中裝的是多個(gè)地址對(duì)象-->
<input type="text" placeholder="請(qǐng)輸入地址" name="add[0].addres"><br>
<input type="text" placeholder="請(qǐng)輸入編碼" name="add[0].code"><br>
<input type="text" placeholder="請(qǐng)輸入地址" name="add[1].addres"><br>
<input type="text" placeholder="請(qǐng)輸入編碼" name="add[1].code"><br>
<!--傳遞單個(gè)地址的實(shí)體對(duì)象-->
<input type="text" placeholder="請(qǐng)輸入地址" name="add.addres"><br>
<input type="text" placeholder="請(qǐng)輸入編碼" name="add.code"><br>
<!--傳遞一個(gè)數(shù)組-->
<input type="checkbox" name="hobby" value="basketball">籃球<br>
<input type="checkbox" name="hobby" value="football">籃球<br>
<input type="checkbox" name="hobby" value="tennis">網(wǎng)球
<input type="submit" value="登錄">
</form>
實(shí)體類
private String username;
private String password;
@DateTimeFormat(pattern="yyyy-MM-dd")
private Date date;
private List<Address> add;
控制器:
@RequestMapping("show5")
public String show5(String[] hobby){
}
全局異常處理
- 1股冗、自定義異常類(繼承Exception或RuntimeException)
public class CustomException extends Exception{
private String msg;
public CustomException(String msg) {
super(msg);
this.msg = msg;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
}
- 2霹陡、自定義異常處理器實(shí)現(xiàn) HandlerExceptionResolver接口
public class ExceptionHandler implements HandlerExceptionResolver{
@Override
public ModelAndView resolveException(HttpServletRequest req, HttpServletResponse resp, Object object,
Exception ex) {
CustomException customException=null;
if (ex instanceof CustomException) {
customException=(CustomException)ex;
}else{
customException=new CustomException("未知錯(cuò)誤");
}
ModelAndView view = new ModelAndView();
view.addObject("error", customException);
view.setViewName("error");
return view;
}
}
- 3、在springmvc配置文件中配置全局異持棺矗控制器
<!-- 定義全局異常 -->
<bean class="com.hemi.exception.handler.ExceptionHandler"></bean>
靜態(tài)資源的釋放
在配置文件中進(jìn)行配置
<!-- 靜態(tài)資源釋放-->
<mvc:resources location="/image/" mapping="/image/*.*"></mvc:resources>
文件上傳
1烹棉、編寫配置文件
<!-- 配置文件上傳處理 -->
<bean id="multipartResolver"
class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!-- 配置默認(rèn)編碼 -->
<property name="defaultEncoding" value="utf-8"></property>
<!-- 配置最大上傳文件大小 -->
<property name="maxUploadSize" value="10485760000"></property>
<!-- 配置最大上傳所用內(nèi)存大小 -->
<property name="maxInMemorySize" value="40960"></property>
</bean>
2、上傳單個(gè)文件怯疤,后端控制器:
public String upload(MultipartFile file,HttpServletRequest req) throws IllegalStateException, IOException{
if(file==null){
return "uploadFile";
}
//取出文件名
String filename = file.getOriginalFilename();
//根據(jù)文件的虛擬入境找到真實(shí)入境
String path = req.getServletContext().getRealPath("/temp");
File file2 = new File(path);
if (!file2.exists()) {
//創(chuàng)建目錄
file2.mkdirs();
}
//將傳入的文件按照真實(shí)入境和文件名寫出來
file.transferTo(new File(file2,filename));
return "success";
}
3浆洗、批量上傳文件,后端控制器
@RequestMapping("/upload1")
public String upload1(MultipartFile[] file,HttpServletRequest req) throws IllegalStateException, IOException{
for (MultipartFile multipartFile : file) {
if(file==null){
return "uploadFile";
}
String filename = multipartFile.getOriginalFilename();
String realPath = req.getServletContext().getRealPath("/team");
File file2 = new File(realPath);
if (!file2.exists()) {
file2.mkdirs();
}
multipartFile.transferTo(new File(file2,filename));
}
return "success";
}
4、編寫前端表單頁(yè)面
<form action="upload" method="post" enctype="multipart/form-data">
請(qǐng)上傳文件:<input type="file" name="file">
<br>
<input type="submit" value="upload">
</form>
<hr>
<form action="upload1" method="post" enctype="multipart/form-data">
請(qǐng)上傳文件:<input type="file" name="file">
<br>
請(qǐng)上傳文件:<input type="file" name="file">
<br>
<input type="submit" value="upload1">
</form>
注意:
把form表單的默認(rèn)的enctype 類型改成 enctype="multipart/form-data"
表單的提交方式設(shè)為:post