SpringMVC入門教程
簡單的HelloWorld示例:
如果往數據庫中存入中文字符的話,則要處理中文亂碼的問題,方法是:
在web.xml中做以下配置:
JSR是記錄Java標準的更新。
輸入驗證:
在實體里使用注解限定屬性:
public class User {
private String username;
private String password;
private String nickname;
private String email;
// 這里加上注解:
@NotEmpty(message="用戶名不能為空")
public String getUsername() {
return username;
}
@Size(min=1,max=10,message="密碼的長度應該在1和10之間")
public String getPassword() {
return password;
}
}
controller中使用@Validate來驗證用戶的輸入,BindingResult返回驗證結果(實體中定義的)
@RequestMapping(value="/{username}/update",
method=RequestMethod.POST)
// BindingResult用來存放錯誤信息(寫在實體里的)
// BindingResult要緊跟@Validate后面
public String update(@PathVariable String username,
@Validated User user,BindingResult br) {
if(br.hasErrors()) {// 有錯誤信息
//如果有錯誤直接跳轉到add視圖
return "user/update";
}
users.put(username, user);
return "redirect:/user/users";
}
//在具體添加用戶時,是post請求,就訪問以下代碼
@RequestMapping(value="/add",method=RequestMethod.POST)
public String add(@Validated User user,BindingResult br,
@RequestParam("attachs")MultipartFile[] attachs,
HttpServletRequest req) throws IOException {
//一定要緊跟Validate之后寫驗證結果類
if(br.hasErrors()) {
//如果有錯誤直接跳轉到add視圖
return "user/add";
}
String realpath = req.getSession().getServletContext().
getRealPath("/resources/upload");
System.out.println(realpath);
for(MultipartFile attach:attachs) {
if(attach.isEmpty()) continue;
File f = new File(realpath+"/"+attach
.getOriginalFilename());
FileUtils.copyInputStreamToFile(attach
.getInputStream(),f);
}
users.put(user.getUsername(), user);
return "redirect:/user/users";
}
然后在jsp頁面顯示這些錯誤信息:
<!-- 此時沒有寫action,直接提交會提交給/add -->
// 這里為什么是直接給/add不明白,可能是modelAttribute=”user”而使用了參數// 匹配吧。
<sf:form method="post" modelAttribute="user"
enctype="multipart/form-data">
// path=”usernama”就相當于是:name=”username”,會自動使用user.Set方法
Username:<sf:input path="username"/>
<sf:errors path="username"/><br/>
Password:<sf:password path="password"/>
<sf:errors path="password"/><br/>
Nickname:<sf:input path="nickname"/><br/>
Email:<sf:input path="email"/>
<sf:errors path="email"/><br/>
Attach:<input type="file" name="attachs"/><br/>
<input type="file" name="attachs"/><br/>
<input type="file" name="attachs"/><br/>
<input type="submit" value="添加用戶"/>
</sf:form>
顯示用戶:
// value=”/{username}” 表示username是一個路徑參數(@PathVariable)
// ?這里的這個username好像是跟show方法中的參數保持一致的……
@RequestMapping(value="/{username}",method=RequestMethod.GET)
public String show(@PathVariable String username,Model model) {
// 在jsp頁面就能用${user.username}取值了
model.addAttribute(users.get(username));
return "user/show";
}
【提示】:
l 關于請求方法:只要不是“更新”操作,就用GET請求。
l 關于model.addAttribute(),如果只寫參數,那么其key則是使用對象的類型比如:
model.addAttribute(new User());等價于:model.addAttribute(“user”,new User());
修改用戶:
// JSP頁面
<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/>
Nickname:<sf:input path="nickname"/><br/>
Email:<sf:input path="email"/>
<sf:errors path="email"/><br/>
<input type="submit" value="修改用戶"/>
</sf:form>
// 頁面跳轉
@RequestMapping(value="/{username}/update",
method=RequestMethod.GET)
public String update(@PathVariable String username,Model model) {
model.addAttribute(users.get(username)); // 回顯
return "user/update";// 到此頁面
}
// 真正的修改
@RequestMapping(value="/{username}/update",
method=RequestMethod.POST)
public String update(@PathVariable String username,
@Validated User user,BindingResult br) {
if(br.hasErrors()) {
//如果有錯誤直接跳轉到add視圖
return "user/update";
}
users.put(username, user);
return "redirect:/user/users";
}
刪除用戶:
<c:forEach items="${users }" var="um">
${um.value.username }
----<a href="${um.value.username }">${um.value.nickname }</a>
----${um.value.password }
----${um.value.email }—
<a href="${um.value.username }/update">修改</a>
<a href="${um.value.username }/delete">刪除</a><br/>
</c:forEach>
@RequestMapping(value="/{username}/delete",
method=RequestMethod.GET)
public String delete(@PathVariable String username) {
users.remove(username);
return "redirect:/user/users";
}
用戶登陸、異常處理:
局部異常處理
局部異常處理是放在一個單獨的Controller中的異常處理,只為這一個Controller服務。
步驟
(1)自定義異常:
public class UserException extends RuntimeException {
private static final long serialVersionUID = 1L;
public UserException() {
super();
}
public UserException(String message, Throwable cause) {
super(message, cause);
}
public UserException(String message) {
super(message);
}
public UserException(Throwable cause) {
super(cause);
}
}
(2)在Controller中使用異常:
@RequestMapping(value="/login",method=RequestMethod.POST)
public String login(String username,String password,
HttpSession session) {
if(!users.containsKey(username)) {
throw new UserException("用戶名不存在");//在頁面可以打印
}
User u = users.get(username);
if(!u.getPassword().equals(password)) {
throw new UserException("用戶密碼不正確");
}
session.setAttribute("loginUser", u);
return "redirect:/user/users";
}
/**
* 局部異常處理,僅僅只能處理這個控制器中的異常
*/
@ExceptionHandler(value={UserException.class})
public String handlerException(UserException e,
HttpServletRequest req) {
req.setAttribute("e",e);
return "error";// 返回到error頁面
}
(3)在error.jsp中顯示異常信息
發現錯誤:
<h1>${e.message}</h1>
全局異常處理
使用方法是在springMVC配置文件中將自己定義的異常配置成全局的。
<bean id="exceptionResolver" class="org.springframework.web.servlet.
handler.SimpleMappingExceptionResolver">
<property name="exceptionMappings">
<props>
// 如果發現UserException就跳轉到error頁面,異常會放在
//exception中,所以在jsp頁面要使用exception來取出異常信息
<prop key="zttc.itat.model.UserException">error</prop>
// 如果發現空指針異常就到error2頁面
<prop key="java.lang.NullPointException">error2</prop>
</props>
</property>
</bean>
在頁面打印異常信息:
發現錯誤:
<h1>${exception.message}</h1>
關于springMVC中的靜態文件
比如,我們在頁面中引用了一個css文件:
</title>
<link rel="stylesheet" href="<%=request.getContextPath()%>/resources/css/main.css" type="text/css">
</head>
然后我們試圖獲取這個文件,比如在瀏覽器中輸入文件地址(或者訪問使用了該樣式的jsp文件,樣式不起作用):
http://localhost:8080/項目名/css/main.css
這時候會報404錯誤。
處理方法是,將所有這些靜態文件放到某個文件夾中,然后在spring配置文件中配置,比如,將main.css文件放到/resources/css/目錄下,然后在spring配置文件中做如下配置:
<!-- 將靜態文件指定到某個特殊的文件夾中統一處理 -->
// location是指要處理的目錄;mapping是指要處理的文件,兩個星的第一個星代表
// 當前文件夾(resources)的內容第二個星表示文件夾的子文件夾的內容
// 注意要加的斜杠
<mvc:resources location="/resources/" mapping="/resources/**"/>
<bean name="/welcome.html" class="zttc.itat.controller.WelcomeController"></bean>
文件上傳:
文件上傳現在一般都用Apache的上傳包:
commons-fileupload-1.2.2-bin
commons-io-2.1
jsp頁面:
<sf:form method="post" modelAttribute="user"
enctype="multipart/form-data">
// path=”usernama”就相當于是:name=”username”,會自動使用user.Set方法
Username:<sf:input path="username"/>
<sf:errors path="username"/><br/>
Password:<sf:password path="password"/>
<sf:errors path="password"/><br/>
Nickname:<sf:input path="nickname"/><br/>
Email:<sf:input path="email"/>
<sf:errors path="email"/><br/>
Attach:<input type="file" name="attachs"/><br/>
<input type="file" name="attachs"/><br/>
<input type="file" name="attachs"/><br/>
<input type="submit" value="添加用戶"/>
</sf:form>
如果想上傳文件就必須在spring配置文件中配置MultipartResolver視圖:
<!-- 設置multipartResolver才能完成文件上傳 -->
<bean id="multipartResolver"class="org.springframework.
web.multipart.commons.CommonsMultipartResolver">
<property name="maxUploadSize" value="5000000"></property>
</bean>
Controller:
//注意:我們上傳一個文件的時候參數只要寫MultipartFile attachs
//這樣上傳的文件自動和attachs做匹配;
//但是如果是上傳多個文件就要用數組MultipartFile[]attachs,這時候文件
//就不能自動匹配了,解決方法是下面的寫法:
@RequestMapping(value="/add",method=RequestMethod.POST)
public String add(@Validated User user,BindingResult br,
@RequestParam("attachs")MultipartFile[] attachs,
HttpServletRequest req) throws IOException {
//一定要緊跟Validate之后寫驗證結果類
if(br.hasErrors()) {
//如果有錯誤直接跳轉到add視圖
return "user/add";
}
String realpath = req.getSession().getServletContext().
getRealPath("/resources/upload");
System.out.println(realpath);
for(MultipartFile attach:attachs) {
//如果多個輸入框有的沒輸入,即有空文件的情況
if(attach.isEmpty()) continue;
File f = new File(realpath+"/"+attach
.getOriginalFilename());
FileUtils.copyInputStreamToFile(attach
.getInputStream(),f);
}
users.put(user.getUsername(), user);
return "redirect:/user/users";
}
Controller中返回JSON:
@RequestMapping(value="/{username}",method=RequestMethod.GET)
public String show(@PathVariable String username,Model model) {
model.addAttribute(users.get(username));
return "user/show";
}
//(1)若要控制返回某個值的話,則要使用@ReponseBody
//(2)params=”par”的意思是,若要訪問show1,那么必須要有一個參數為par
// 如果沒有參數就訪問上面的這個show了
@RequestMapping(value="/{username}",
method=RequestMethod.GET,params="par")
@ResponseBody
public User show(@PathVariable String username) {
return users.get(username);
}
【說明】:
訪問第一個show的方式:http://localhost:8080/項目名/user/jack/
訪問第二個show的方式:http://localhost:8080/項目名/user/jack?par
(這樣直接訪問的話,會報406錯誤,缺少http頭)
如果想返回一個json,首先導入轉json的開發包:jackson-all-1.9.4.jar
然后再訪問第二個show:http://localhost:8080/項目名/user/jack?par
這樣就直接將user轉成json格式顯示。
用戶管理
l 新建項目
l 拷貝jar包(Spring的dist目錄下的jar包,Apache的log4j、commons-loggin)
commons-dbcp、commons-collections、commons-pool
l </span></span>