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>