根据选中的商品ID进行删除
@RequestMapping("/batchDeleteSave") public String batchDeleteSave(Long[] ids,UserVo vo) { System.out.println("---");
return "success"; } |
<delete id="batchDeleteUser" parameterType="Long[]" > delete from user <where> <foreach collection="array" item="id" open="and id in(" close=")" separator="," > #{id} foreach> where> delete> |
把数据绑定到List集合
private List
public List return users; }
public void setUsers(List this.users = users; } |
<tr> <td>用户名称td> <td><input type="text" name="users[0].username" value="${user.username }" />td> tr> <tr> <td>生日td> <td><input type="text" name="users[0].birthday" value="<fmt:formatDate value="${user.birthday}" pattern="yyyy-MM-dd" />" />td> tr> <tr> <td>性别td> <td> <select name="users[0].sex" > <option value="1" <c:if test="${user.sex=='1'}">selected="selected"c:if> >男option> <option value="2" <c:if test="${user.sex=='2'}">selected="selected"c:if> >女option> select> td> tr> |
@RequestMapping(value="/addUser",method=RequestMethod.POST) public String addUserVo(UserVo vo) { System.out.println("...."); return "addUser"; } |
作用:通过requestMapping注解可以定义不同的处理器映射规则。
可以在class上面加上RequestMapping(url)指定通用的请求前缀。
@Controller @RequestMapping("/user") public class UserController { |
@RequestMapping(value={"/ceshi1","/ceshi2"},method=RequestMethod.POST) public String ceshi(UserVo vo) { System.out.println("...."); return "addUser"; } |
Controller方法中定义ModelAndView对象并返回,对象中可添加model数据,指定view视图。
//model可以配合返回值进行逻辑视图的跳转。 model.addAttribute("name","张三"); //return "url"
//modelAndView modelAndView.setViewName("url"); modelAndView.addObject("name","李四"); |
在controller方法形参上可以定义request和reresponse,使用requset和response指定响应结果。
//转发 request.getRequestDispatcher("/WEB-INF/adduser.jsp").forward(request, response);
//重定向 response.sendRedirect("/user/addUser.do");
//返回json格式的数据 response.setCharacterEncoding("utf-8"); response.setContentType("application/json;charset=utf-8"); //设置响应正文的编码格式 // response.setContentType("text/json;charset=utf-8") response.getWriter().println("/{/"aa"/:/"bb"/}/"); jackson fastJSON |
|
Ajax接受服务端响应的json字符串,{“username”:”张三”,”password”:”123”}; [object][object]
var data =xmlHttpRequest.ResponseText;
alert(data); {“username”:”张三”,”password”:”123”}
怎么把JSON字符串编程对象? Var data = eval(“(“+data+”)”)
data.username
客户端使用的是原生ajax xmlHttpRequest
var data = xmlHttpRequest.ResponseXml
客户端可以接受的响应数据格式
Controller 方法返回字符串可以指定逻辑视图名,通过视图解析器解析为物理视图地址。
return "url"; |
Contrller方法返回结果重定向到另外一个url地址。
return "redirect:/user/getUserList.do"; |
return "forward:/user/getUserList.do"; |
注意:逻辑试图返回的字符串默认就是转发
Springmvc在处理请求过程中出现异常信息通常交由异常处理器进行处理,自定义异常处理器可以实现一个系统的异常处理逻辑。
系统中异常包括两类。预期异常和运行时异常RuntimeException,前面的通过捕获异常从而获取异常信息,后面主要通过代码规范开发,测试减少运行时异常的发生。
异常处理思路图:
为了区别不同的异常通常会根据异常类型自定义异常类,这里我们创建一个自定义系统异常,如果controller service dao抛出异常说明是系统预期处理的异常信息。
public CustomException() { }
public CustomException(String message) { this.message = message; }
//异常信息 private String message;
public String getMessage() { return message; }
public void setMessage(String message) { this.message = message; } |
要实现全局异常处理,就要实现HandlerExceptionResolver接口。
String message = null;
//1.判断抛出的异常是否是系统自定义异常 if(ex instanceof CustomException) { CustomException c = (CustomException)ex; message = c.getMessage(); }else { //2.如果不是系统自定义的异常 //3.打印异常信息 ex.printStackTrace();
//把异常信息输出 StringWriter sw = new StringWriter(); PrintWriter pw = new PrintWriter(sw); ex.printStackTrace(pw); //写日志 log4j logback message = sw.toString(); }
ModelAndView modelAndView = new ModelAndView(); modelAndView.addObject("message", message); modelAndView.setViewName("error"); return modelAndView; |
<body>
<h6>错误页面:h6> <h1>${message}h1> body> |
|
public String ceshi5() throws CustomException { //1. 测试自定义异常 // if(true) { // throw new CustomException("系统错误,请等待!"); // } //2. 非自定义异常 int i = 1/0; return "success"; } |
图片上传的三要素:
<form id="itemForm" action="/springmvc-02/addUser.do" method="post" enctype="multipart/form-data" > <input type="hidden" name="id" value="${user.id }" /> 添加用户信息: <table width="100%" border=1> <tr> <td>用户名称td> <td><input type="text" name="users[0].username" value="${user.username }" />td> tr> <tr> <td>生日td> <td><input type="text" name="users[0].birthday" value="<fmt:formatDate value="${user.birthday}" pattern="yyyy-MM-dd" />" />td> tr> <tr> <td>性别td> <td> <select name="users[0].sex" > <option value="1" <c:if test="${user.sex=='1'}">selected="selected"c:if> >男option> <option value="2" <c:if test="${user.sex=='2'}">selected="selected"c:if> >女option> select> td> tr> <tr> <td>上传图像td> <td><input type="file" name="picfile"/>td> tr> <tr> <td colspan="2" align="center"><input type="submit" value="提交" /> td> tr> table> form> |
因为springmvc默认不支持图片上传,所以需要配置解析器。
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"> 文件最大不能超过5兆 --> <property name="maxUploadSize" value="5242880" /> bean> |
1. 在class上面需要配置@MultiparConfig
2. MultipartFile的名称必须和表单的name保持一致
3. 创建图片保存的位置
代码的编写:
@RequestMapping(value="/addUser",method=RequestMethod.POST) public String addUserVo(MultipartFile picfile,HttpServletRequest request) throws IllegalStateException, IOException { //1. 获得图片的名称 String filename = picfile.getOriginalFilename();
//2. 获得图片保存在服务器的路径 String realPath = request.getServletContext().getRealPath("/imgs");
//3. 把图片上传到服务器 picfile.transferTo(new File(realPath+"/"+filename));
return "addUser"; } |
response.setContentTyep(‘’text/xml;charset=utf-8’);
作用:
requestBody注解用于将json格式的请求参数绑定controller的方法的参数上面。
请求参数,{“username”:”张三”,”address”:”武汉宏鹏”} 可以通过requestBody标签使用对象来接收数据。底层是通过springmvc的HttpMessageConverter接口将读取到的内容转换成json,xml绑定到方法的参数上。
作用:
可以将响应的数据转换成为json响应给客户端。
<button onclick="sendJsonTest();" >提交Json数据button> <script type="text/javascript"> function sendJsonTest() { $.ajax({ type:"post", url:"${pageContext.request.contextPath}/user/ceshi7.do", contentType:"application/json;charset=utf-8", success:function(data) { alert(data); } }); }
script> |
评价:这里应该是掉了一个data
@RequestMapping("/ceshi7.do") @ResponseBody public User ceshi7(@RequestBody User user) { System.out.println(user.toString()); return user; } |
一种软件架构风格,设计风格而不是标准,只是提供了一组设计原则和约束条件。它主要用于客户端和服务器交互类的软件。基于这个风格设计的软件可以更简洁,更有层次,更易于实现缓存等机制。
资源定位:互联网所有的事物都是资源,要求URL中没有动词,只有名次,没有参数。
访问查询用户 http://localost/springmvc02/user/selectUserById.do?id=1
Restful软件架构风格:http://localhost/springmvc02/user/selectUserById/1
资源操作:使用put delete post get使用不同方法对资源进行操作。分别对应添加,删除,修改,查询。
<servlet-mapping> <servlet-name>springmvcservlet-name>
<url-pattern>/url-pattern> servlet-mapping> |
/** * 使用restful风格实现通过ID查询用户 */ @RequestMapping("/selectUserById/{id}") public void selectUserById(@PathVariable("id") String id) { //去数据库查询就可以了 System.out.println(id); } |
评价:这个@PathVariable 主要就是做一个参数的映射
<mvc:resources location="/js/" mapping="/js/**"/> |
评价:由于上面拦截了所有的资源,所有这里报出了未定义$的错误,这里需要再加载静态资源
springWebMvc的处理器拦截器类似于过滤器Filter,用于对处理器进行预处理和后处理。
需要实现HanderInterceptor接口
/** * handler执行前调用此方法 * 如果返回true表示继续执行,返回false停止执行 * 实际开发中可以加入登录校验,权限拦截等。。。 */ @Override public boolean preHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2) throws Exception { System.out.println("CustomInterceptor1 preHandler"); return false; }
/** * handler执行后但未返回视图前调用此方法 * 这里可以在返回视图前对模型数据进行处理,比如可以加入通用的信息进行页面的显示 */ @Override public void postHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, ModelAndView modelAndView) throws Exception { System.out.println("CustomInterceptor1 postHandle"); }
/** * hadnler执行后且视图返回后调用次方法 * 这里记录记录操作日志,资源清理,还可以得到异常信息。 */ @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println("CustomInterceptor1 afterCompletion"); } |
import com.github.pagehelper.StringUtil;
import com.urovo.config.Constants;
import com.urovo.exception.TokenException;
import com.urovo.model.TokenModel;
import com.urovo.util.i18n.I18nMessage;
import com.urovo.util.token.TokenUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@Slf4j
public class AccessTokenInterceptor extends HandlerInterceptorAdapter {
@Autowired
private I18nMessage i18nMessage;
@Autowired
private TokenUtils tokenUtils;
@Autowired
private RedisTemplate redisTemplate;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//token校验
if ((((HandlerMethod) handler).getBeanType().getName().equals("com.urovo.controller.LoginController"))) {
String ac_token = request.getHeader(Constants.AUTH_CODE_token);
Object o = redisTemplate.boundValueOps(Constants.AUTH_CODE + ac_token).get();
if (o != null) {
String code = (String) o;
request.setAttribute(Constants.CURRENT_REQUEST_KAPTCHA, code);
}
return true;
}
//从请求参数和请求头中取出uid,token
String uid = request.getHeader(Constants.UID);
String token = request.getHeader(Constants.AUTHORIZATION);
if (StringUtil.isEmpty(token) || StringUtil.isEmpty(uid)) {
throw new TokenException(i18nMessage.getMessage("token.uid.none"));
}
//redis token 校验
TokenModel tm = new TokenModel(uid, token);
if (tokenUtils.checkToken(tm)) {
request.setAttribute(Constants.CURRENT_USER_ID, tm.getUserId());
request.setAttribute(Constants.CURRENT_USER_TOKEN, tm.getToken());
//从缓存获取公司和公司子节点编号数据
String company_node = (String)redisTemplate.boundValueOps(Constants.USER_COMPANY_NODE+tm.getUserId()).get();
String[] split = company_node.split(":");
request.setAttribute(Constants.CURRENT_USER_COMPANY,split[0]);
if ( split.length > 1 ) {
if ( "null".equalsIgnoreCase(split[1])) {
split[1] = null;
}
request.setAttribute(Constants.CURRENT_USER_COMPANY_NODE,split[1]);
}
return true;
} else {
throw new TokenException(i18nMessage.getMessage("token.invalid"));
}
}
}
多重拦截器的执行顺序:
CustomInterceptor1 preHandler CustomInterceptor2 preHandler 123 CustomInterceptor2 postHandle CustomInterceptor1 postHandle CustomInterceptor2 afterCompletion CustomInterceptor1 afterCompletion |
需求分析:用户登录的拦截
3 拦截器
<h3>用户登录:h3> <form action="/springmvc-02/user/login.do" method="post" > 用户名:<input type="text" name="username" >br> 密码:<input type="password" name="password" /> <input type="submit" value="提交" > form> |
Controller代码的编写:
@RequestMapping(value="/login",method=RequestMethod.POST) public String userLogin(String username,String password,HttpSession session) { //用户登录成功,把用户的信息放入session域 session.setAttribute("username",username); return "success"; } |
@Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//如果是访问的登录页面,那么就放行 String url = request.getRequestURI(); if(url.contains("login")) { return true; } //如果用户已经登录那么也放行 Object usernmae = request.getSession().getAttribute("username"); if(usernmae != null) { return true; }
//用户没有登录跳转到登录页面 request.getRequestDispatcher("/WEB-INF/jsp/login.jsp").forward(request, response); return false; } |