常見MVC架構比較
運行效能上:
Jsp+servlet>struts1>spring mvc>struts2+freemarker>>struts2,ognl,值棧。
開發效率上,基本正好相反。值得強調的是,spring mvc開發效率和struts2不相上下。
Struts2的效能低的原因是因為OGNL和值棧造成的。所以,如果你的系統並發量高,可以使用freemaker進行顯示,而不是採用OGNL和值棧。這樣,在效能上會有相當大得提高
1.環境搭建web.xml
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5"><servlet> <servlet-name>dispatcherServlet</servlet-name> <servlet-class> org.springframework.web.servlet.DispatcherServlet </servlet-class> <init-param> <!-- 不設定此內容的話,會預設載入:<servlet-name>標籤內名字+"-servlet”的xml,即dispatcherServlet-servlet.xml--> <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/web-config.xml</param-value><!-- 有多個設定檔,中間用,隔開 --> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>dispatcherServlet</servlet-name> <url-pattern>/</url-pattern> <!-- 所有請求都捕獲 --> </servlet-mapping></web-app>
web-config.xml:
<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context"xmlns:mvc="http://www.springframework.org/schema/mvc"xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsdhttp://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd"><mvc:annotation-driven/><context:component-scan base-package="com.test.controller" /><mvc:resources location="/resources/" mapping="/resource/**"/><!-- 指定靜態資源(請求不被spring過濾)如css,js等的位置 ,css路徑應是mapping中的路徑--><!-- 頁面View層基本資料設定 --> <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/> <!-- 如果使用jstl的話,配置的屬性 --> <property name="suffix" value=".jsp"/> <!-- 尾碼 --> <property name="prefix" value="/WEB-INF/jsp/" /> <!-- 首碼 --> </bean> <!-- 處理檔案上傳 --><bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver" > <property name="defaultEncoding" value="utf-8"/> <!-- 預設編碼 (ISO-8859-1) --> <property name="maxInMemorySize" value="10240"/> <!-- 最大記憶體大小 (10240)--> <property name="uploadTempDir" value="/upload/"/> <!-- 上傳後的目錄名 (WebUtils#TEMP_DIR_CONTEXT_ATTRIBUTE) --> <property name="maxUploadSize" value="-1"/> <!-- 最大檔案大小,-1為無限止(-1) --> </bean></beans>
常用註解使用方法如下例子的注釋:
@Controller@SessionAttributes({"param","se"})////擷取session,將ModelMap中屬性名稱字為param、se的再放入session中,這樣,request和session中都有了。@RequestMapping(value="user") //--1 @RequestMapping在類前面定義,則將url和類綁定。在方法前面定義,則將url和類的方法綁定public class HelloController {@RequestMapping(value={"/hello2","/hello"},params="method=do") //--2 value指定多個值,可以多個訪問路徑public String hello() {return "hello"; //根據設定將跳到/WEB-INF/jsp/hello.jsp中}// 1、2處如果同時定義了路徑則是兩處的疊加 上面的這個訪問路徑://http://localhost:8080/springMVC/user/hello2?method=do http://localhost:8080/springMVC/user/hello?method=do//擷取傳過來的值 直接用參數就可以擷取@RequestMapping(params="param=do") //http://localhost:8080/springMVC/user?param=do&name=ljf&age=22&id=1&uname=testpublic String serv(int id,@RequestParam String name,@RequestParam("age") int old,User u){ //@RequestParam 註解用來表示傳來的參數不和形參一致解決方法System.out.println(u.getUname()+" "+id+" "+name+" "+old); //傳過來的值會和對象屬性名稱字自動匹配return "hello";}//傳過來的值不能少,如果少了任一個就會出錯,少id會報異常,少name,age會報404找不到路徑//值返回去 用map 或者 model 它們的值就會存在request域中@RequestMapping //http://localhost:8080/springMVC1/userpublic String say(Map<String, Object> map,Model model,HttpServletRequest req,HttpSession session) {//擷取request,sessionmap.put("param", "v1");model.addAttribute("p1", "v2");//使用Object的類型作為key,String-->stringUser u=new User("ljf");model.addAttribute("ok");//${string}model.addAttribute(u); //${user.uname}session.setAttribute("se", "se");return "hello";}@RequestMapping("/req")public String req(@ModelAttribute("se") String name) { //@ModelAttribute 把session中的"se"賦給name,注意,如果session中沒有,將報錯System.out.println(name);return "hello"; }//ModelAndView模型視圖類//從名字上可以知道ModelAndView中的Model代表模型,View代表視圖。即,這個類把要顯示的資料存放區到了Model屬性中,要跳轉的視圖資訊儲存到了view屬性@RequestMapping(params="method=reg6")public ModelAndView reg6(String uname){ModelAndView mv = new ModelAndView();mv.setViewName("hello");//mv.setView(new RedirectView("index"));User u = new User("abc");mv.addObject(u); //查看原始碼,得知,直接放入對象。屬性名稱為”首字母小寫類名”。 一般建議手動增加屬性名稱。mv.addObject("a", "aaaa");return mv;}}
和Struts1一樣,Spring的Controller是Singleton的。這就意味著會被多個請求線程共用。因此,我們將控制器設計成無狀態類。(和struts2不一樣,因為函數的參數是唯一的)
核心原理
1.使用者發送請求給伺服器。url:user.do
2.伺服器收到請求。發現DispatchServlet可以處理。於是調用DispatchServlet。
3.DispatchServlet內部,通過HandleMapping檢查這個url有沒有對應的Controller。如果有,則調用Controller。
4.Controller開始執行。
5.Controller執行完畢後,如果返回字串,則ViewResolver將字串轉化成相應的視圖對象;如果返回ModelAndView對象,該對象本身就包含了視圖對象資訊。
6.DispatchServlet將執視圖對象中的資料,輸出給伺服器。
7.伺服器將資料輸出給用戶端。
spring 轉寄,重新導向
@RequestMapping(value="/add",method=RequestMethod.POST)public String add(@Valid User user,BindingResult bind){if(bind.hasErrors())return "user/add";users.put(user.getUsername(),user);return InternalResourceViewResolver.REDIRECT_URL_PREFIX+"/user/users";//"forward:user.do"; 默認轉寄//重新導向return "redirect:user.do"; }
spring採用rest形式訪問資源,以資源為導向
@RequestMapping(value="/{username}/update",method=RequestMethod.GET)//**************加{}public String update(@PathVariable String username,Model model){//@PathVariable 路徑變數username即為路徑中的內容:{}中內容model.addAttribute(users.get(username));return "user/update";}
下面是一個使用者管理的準系統:
user類:
public class User {private String username;private String password;private String email;public User() {super();}public User(String username, String password, String email) {super();this.username = username;this.password = password;this.setEmail(email);}@NotEmpty(message="使用者名稱不可為空")public String getUsername() {return username;}public void setUsername(String username) {this.username = username;}@NotEmpty(message="密碼不可為空") @Size(max=10,min=4)public String getPassword() { return password;}public void setPassword(String password) {this.password = password;}@NotEmpty(message="郵箱不可為空")@Email(message="郵箱格式不正確")public String getEmail() {return email;}public void setEmail(String email) {this.email = email;}}
處理user異常的類:
public class UserException extends RuntimeException{public UserException() {super();}public UserException(String message, Throwable cause) {super(message, cause);}public UserException(String message) {super(message);}public UserException(Throwable cause) {super(cause);}}
controller類:
@Controller@RequestMapping("/user")public class UserController {private final static Map<String,User> users=new HashMap<String, User>();public UserController(){users.put("ldh",new User("ldh", "123", "123123"));users.put("zxy",new User("zxy", "123", "123123"));users.put("gfc",new User("gfc", "123", "123123"));users.put("lm",new User("lm", "123", "123123"));}@RequestMapping(value={"users","/"})public String list(Model model){model.addAttribute("users", users);return "user/list";}@RequestMapping(value="/add",method=RequestMethod.GET) //method 屬性要求請求方式必須是get public String add(Model model){model.addAttribute(new User());// 這步不能少,如果是new User("a","b","c"),則表單裡顯示user內容 return "user/add";}/*驗證欄位:springMVC使用 JSR-303 Validator(java標準)驗證, 可以查看 JSR 303 - Bean Validation文檔, 需要bean-validator.jar然後在實體類中採用註解形式標明驗證條件 ,在調用方法中使用@Valid指明驗證的model,以及用BindingResult儲存錯誤資訊,在頁面中用spring form表單顯示錯誤*/@RequestMapping(value="/add",method=RequestMethod.POST)public String add(@Valid User user,BindingResult bind){if(bind.hasErrors())return "user/add";users.put(user.getUsername(),user);return InternalResourceViewResolver.REDIRECT_URL_PREFIX+"/user/users";//"forward:user.do"; 默認轉寄//重新導向return "redirect:user.do"; }@RequestMapping(value="{username}",method=RequestMethod.GET) public String show(@PathVariable String username,Model model){ model.addAttribute(users.get(username));return "user/show";} /**spring採用rest形式訪問資源,以資源為導向**/@RequestMapping(value="/{username}/update",method=RequestMethod.GET)//**************加{}public String update(@PathVariable String username,Model model){//@PathVariable 路徑變數username即為路徑中的內容:{}中內容model.addAttribute(users.get(username));return "user/update";}@RequestMapping(value="/{username}/update",method=RequestMethod.POST)public String update(@PathVariable String username,@Valid User user,BindingResult bind){//bind一定要緊跟在User之後if(bind.hasErrors())return "user/update";users.put(username, user);return "redirect:/user/users";}@RequestMapping("ex")public String ex(){ //測試處理異常if(true)throw new UserException("使用者出現錯誤 !");return "user/users";}//異常處理 @ExceptionHandler(value={Exception.class}) //此處是Exception.class,所以可以處理所有的異常public String handlerException(Exception ex,HttpServletRequest req){req.setAttribute("ex", ex);return "user/error"; //轉寄到error.jsp,${error.message}輸出錯誤資訊}}
add.jsp:
<%@ page language="java" pageEncoding="UTF-8"%><%@ taglib prefix="sf" uri="http://www.springframework.org/tags/form" %><!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"><html><head><title>title</title> <link rel="stylesheet" href="/springMVC2/resource/css/main.css" type="text/css"/> <!-- 此處是mapping位置 --></head><body><sf:form method="post" modelAttribute="user" >username:<sf:input path="username"/> <sf:errors path="username"/><br>password:<sf:password path="password"/><sf:errors path="password"/><br>email:<sf:input path="email"/><sf:errors path="email"/><br><input type="submit" value="提交" />;</sf:form></body></html>
檔案上傳:用到commons-fileupload.jar,commons-io.jar
@RequestMapping(value="/upload", method = RequestMethod.POST)//要求form表單以post方式上傳public String handleUploadData(String name,@RequestParam("file") CommonsMultipartFile file){//多檔案 多檔案MultipartFile[] file用for處理if (!file.isEmpty()) { String path = this.servletContext.getRealPath("/tmp/"); //應放在指定的靜態資源檔案中<mvc:resource />,擷取本機存放區路徑 儲存在了D:\study\apache-tomcat-6.0.35\webapps\test\tmp System.out.println(path); String fileName = file.getOriginalFilename();//擷取檔案名稱 String fileType = fileName.substring(fileName.lastIndexOf(".")); System.out.println(fileType); File file2 = new File(path,new Date().getTime() + fileType); //建立一個檔案 try { file.getFileItem().write(file2); //將上傳的檔案寫入建立的檔案中 } catch (Exception e) { e.printStackTrace(); } return "redirect:upload_ok.jsp";}else{return "redirect:upload_error.jsp";}}