SpringMVC入门教程

jopen 10年前

简单的HelloWorld示例:

如果往数据库中存入中文字符的话,则要处理中文乱码的问题,方法是:

SpringMVC入门教程

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="密码的长度应该在110之间")

    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

//2params=”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

然后再访问第二个showhttp://localhost:8080/项目名/user/jack?par

这样就直接将user转成json格式显示。

用户管理

l  新建项目

l  拷贝jar包(Springdist目录下的jar包,Apachelog4jcommons-loggin

commons-dbcpcommons-collectionscommons-pool

l  </span></span>