Spring和Springmvc知识点以及Cookie使用总结(个人学习资料)

未分类 发表评论


1、关于在jsp页面中日期的格式化问题

<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt"%>
<fmt:formatDate value="${user.birth}" pattern="yyyy-MM-dd HH:mm:ss" /></td>
<input type="text" name="birth" value="<fmt:formatDate value='${user.birth}' pattern='yyyy-MM-dd HH:mm:ss' />" />

2、Controller中的方法返回值问题

  • 逻辑视图名:controller方法返回字符串可以指定逻辑视图名,通过视图解析器解析为物理视图地址
@GetMapping("/list")
public String getUsers(Model model){
    List<User> list = userService.getUsers();
    model.addAttribute("list",list);
    return "success";
}
  • Redirect重定向:Contrller方法返回字符串可以重定向到一个url地址
/**
 * Redirect:重定向
 * 重定向后浏览器地址栏变更为重定向的地址
 * 重定向相当于执行了新的request和response,所以之前的请求参数都会丢失
 * 如果要指定请求参数,需要在重定向的url后面添加 ?itemId=1 这样的请求参数
 */
@PostMapping("/update")
public String update(User user){
    userService.updateUser(user);
    return "redirect:/list";
}
  • forward转发:Controller方法执行后继续执行另一个Controller方法
/**
 * forward:请求转发
 * 使用转发的方式实现,转发后浏览器地址栏还是原来的请求地址;
 * 转发并没有执行新的request和response,所以之前的请求参数都存在
 * 效果:在forward.jsp页面中,可以利用jstl表达式取出username的值;
 * model相当于把值放入request域中,如果用请求转发的方式,可以把model中的值传入下一个jsp页面中;
 */
@GetMapping("/forward")
public String testForward(Model model){
    model.addAttribute("username","冯朗");
    return "forward:/testforward";
}

/**
*进入forward.jsp页面
*/
@GetMapping("/testforward")
public String forward(Model model){
    List<String> list=new ArrayList<>();
    list.add("冯朗");
    list.add("冯跃");
    list.add("李晓丹");
    list.add("李佩丹");
    list.add("郑艳玲");
    list.add("郑玲玲");
    model.addAttribute("list",list);
    return "forward";
}

3、异常处理思路:系统中异常包括两类:预期异常和运行时异常RuntimeException,前者通过捕获异常从而获取异常信息,后者主要通过规范代码开发、测试通过手段减少运行时异常的发生.

  • 自定义异常处理方式一
/**
 * 自定义异常
 */
public class BusinessException extends Exception {

    private static final long serialVersionUID = -3877632972829688761L;

    private String message;

    public BusinessException(String message) {
        super();
        this.message = message;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

}

/**
 * 全局异常处理
 * 方法一:
 */
@ControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(value={BusinessException.class,Exception.class})
    public ModelAndView handkeException(Exception ex) {
        ModelAndView modelAndView=new ModelAndView();
        modelAndView.addObject("msg",ex.getMessage());
        modelAndView.setViewName("error");
        return modelAndView;
    }

}

/**
 * 此方法抛出的异常由GlobalExceptionHanlder处理;
 * @return
 * @throws Exception
 */
@SuppressWarnings("unused")
@GetMapping("/testexception")
public String testException(CustomBean user) throws Exception{
    if(true){
        throw new SQLException("SQL错误");
    }
    int i=1/0;
    return "forward";
}

/**注意:
 * 在Controller中抛出的异常,当没有被catch处理时,
 * GlobalExceptionHandler中定义的处理方法可以起作用!
 * 此方法抛出的异常由GlobalExceptionHanlder处理;
 * @return
 * @throws Exception
 */
@GetMapping("/exception")  
   public String exception() throws Exception {   
       throw new BusinessException("业务执行异常");  
   } 

/**
 * 此方法抛出的异常不是由GlobalExceptionHandler处理,
 * 而是在catch代码块内进行处理;
 */
@GetMapping("/exceptions")  
   public String exceptions(){   
       try {
        throw new BusinessException("业务执行异常");
    } catch (BusinessException e) {
        e.printStackTrace();
    }  
       return "forward";
   } 
  • 自定义异常处理方式二
/**
 * 全局异常处理
 * 方法二:
 */
@Component
public class CustomExceptionResolver implements HandlerExceptionResolver {

    @Override
    public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler,Exception ex) {
        String msg="";
        if(ex instanceof BusinessException){
            BusinessException exception=(BusinessException)ex;
            msg=exception.getMessage();
        }else{
            msg=ex.getMessage();
        }
        ModelAndView modelAndView=new ModelAndView();
        modelAndView.addObject("msg",msg);
        modelAndView.setViewName("error");
        return modelAndView;
    }

}

在error.jsp中展示错误信息;
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>错误页</title>
</head>
<body>
    <h2>${msg}</h2>
</body>
</html>

4、Spring拦截器的使用(参考资料:Interceptor)

  • 自定义拦截器,实现HandlerInterceptor接口
/**
 * 自定义拦截器1
 */
public class CustomInterceptor implements HandlerInterceptor {

    /**
     * Controller执行前调用此方法,这里可以加入登录校验、权限拦截等
     * return:true代表放行;false代表拦截,终止执行;
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {
        System.out.println("-------preHandle");
        HttpSession session = request.getSession();
        String username=(String) session.getAttribute("username");
        if(username!=null){
            return true;
        }else{
            response.sendRedirect(request.getContextPath()+"/login");
            return false;
        }
    }

    /**
     * controller执行后但未返回视图前调用此方法
     * 这里可在返回用户前对模型数据进行加工处理,比如这里加入公用信息以便页面显示
     */
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
            ModelAndView modelAndView) throws Exception {
        System.out.println("----------->postHandle");
    }

    /**
     * controller执行后且视图返回后调用此方法
     * 这里可得到执行controller时的异常信息
     */
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
            throws Exception {
        System.out.println("----------->afterCompletion");
    }

}


/**
 * 自定义拦截器2
 */
public class CustomInterceptor2 implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {
        System.out.println("----------->preHandle222-->"+request.getRequestURI());
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
            ModelAndView modelAndView) throws Exception {
        System.out.println("----------->postHandle222");
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
            throws Exception {
        System.out.println("----------->afterCompletion222");
    }

}
  • 在springmvc中配置拦截器
<!-- 配置拦截器 -->
<mvc:interceptors>

    <mvc:interceptor>
        <!-- 所有的请求都进入拦截器 -->
        <mvc:mapping path="/**"/>
        <!-- 配置不拦截的路径-->
        <mvc:exclude-mapping path="/login"/>
        <mvc:exclude-mapping path="/sendget"/>
        <mvc:exclude-mapping path="/resource/**"/>
        <!-- 配置具体的拦截器 -->
        <bean class="com.security.interceptor.CustomInterceptor"/>
    </mvc:interceptor>

    <mvc:interceptor>
        <mvc:mapping path="/**"/>
        <bean class="com.security.interceptor.CustomInterceptor2"/>
    </mvc:interceptor>

</mvc:interceptors>
  • 拦截器运行流程分析

    ①HandlerInterceptor1的preHandler方法返回false,HandlerInterceptor2返回true,运行流程如下:
    HandlerInterceptor1..preHandle..
    从日志看出第一个拦截器的preHandler方法返回false后第一个拦截器只执行了preHandler方法,其它两个方法没有执行,第二个拦截器的所有方法不执行,且Controller也不执行了。

    ②HandlerInterceptor1的preHandler方法返回true,HandlerInterceptor2返回false,运行流程如下:
    HandlerInterceptor1..preHandle..
    HandlerInterceptor2..preHandle..
    HandlerInterceptor1..afterCompletion..
    从日志看出第二个拦截器的preHandler方法返回false后第一个拦截器的postHandler没有执行,第二个拦截器的postHandler和afterCompletion没有执行,且controller也不执行了。

    总结:
    preHandle按拦截器定义顺序调用
    postHandler按拦截器定义逆序调用
    afterCompletion按拦截器定义逆序调用

    postHandler在拦截器链内所有拦截器返回成功调用
    afterCompletion只有preHandle返回true才调用

5、Listener上下文监听,初始化WEB容器

/**
 * WEB容器初始化时调动;
 */
@Component
public class ContextRefreshListener implements ApplicationListener<ContextRefreshedEvent>,ServletContextAware{

    @Autowired
    private UserService service;

    private ServletContext servletContext;

    /**
     * 上下文刷新事件
     */
    @Override
    public void onApplicationEvent(ContextRefreshedEvent event) {
        if(event.getApplicationContext().getParent()==null){
            System.out.println("---------->web容器初始化");
            User user=service.getUserById(1);
            //相当于把User对象放入Application中;
            servletContext.setAttribute("user",user);
        }
    }

    @Override
    public void setServletContext(ServletContext servletContext) {
        this.servletContext=servletContext;
    }

}

6、cookie的使用(借助插件jquery.coolie.js)

<form action="/login" method="post">
    <input type="text" name="username" id="username"/><br/>
    <input type="checkbox" name="remember" id="rememberme"/>记住我<br/>
    <input type="submit" value="LOGIN"/>
</form>


<script type="text/javascript" src="/resource/js/jquery.js"></script>
<script type="text/javascript" src="/resource/js/jquery.cookie.js"></script>
<script type="text/javascript">
    $(function(){
        var COOLIE_NAME="username";
        if($.cookie(COOLIE_NAME)){
            $("#username").val($.cookie(COOLIE_NAME));
            $("#rememberme").attr("checked","checked");
        }

        $("#rememberme").click(function(){
            if(this.checked){
                $.cookie(COOLIE_NAME,$("#username").val(),{path:'/',expires:10});
            }else{
                $.cookie(COOLIE_NAME,null,{path:'/'});
            }
        });
    });
</script>

7、Cookie介绍:Cookie技术是将用户的数据存储到客户端的技术

7.1 服务器端向客户端发送一个Cookie

  • 创建Cookie
    Cookie cookie = new Cookie(String cookieName,String cookieValue);
    示例:Cookie cookie = new Cookie(“username”,”zhangsan”);
    那么该cookie会以响应头的形式发送给客户端:
    注意:Cookie中不能存储中文

  • 设置Cookie在客户端的持久化时间
    cookie.setMaxAge(int seconds); 时间单位为秒
    注意:如果不设置持久化时间,cookie会存储在浏览器的内存中,浏览器关闭cookie信息销毁(会话级别的cookie),如果设置持久化时间,cookie信息会被持久化到浏览器的磁盘文件里
    示例:cookie.setMaxAge(10*60);
    设置cookie信息在浏览器的磁盘文件中存储的时间是10分钟,过期浏览器自动删除该cookie信息

  • 设置Cookie的携带路径
    cookie.setPath(String path);
    注意:如果不设置携带路径,那么该cookie信息会在访问产生该cookie的web资源所在的路径都携带cookie信息
    示例:cookie.setPath(“/WEB16”) 代表访问WEB16应用中的任何资源都携cookie
    cookie.setPath(“/WEB16/cookieServlet”)代表访问WEB16中的cookieServlet时才携带cookie信息

  • 向客户端发送cookie
    response.addCookie(Cookie cookie);

  • 删除客户端的cookie
    如果想删除客户端的已经存储的cookie信息,那么就使用同名同路径的持久化时间为0的cookie进行覆盖即可

7.2 服务器端怎么接受客户端携带的Cookie:cookie信息是以请求头的方式发送到服务器端的

  • 通过request获得所有的Cookie
   Cookie[] cookies = request.getCookies();
  • 遍历Cookie数组,通过Cookie的名称获得我们想要的Cookie
for(Cookie cookie : cookies){
    if(cookie.getName().equal(cookieName)){
        String cookieValue = cookie.getValue();
    }
}

7.3 Cookie的使用

  • 如果用户在登录时设置自动登录,则保存cookie,并发送到服务端;
//表单验证
public void doPost(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException {
    String username=request.getParameter("username");
    String password=request.getParameter("password");
    String authLogin=request.getParameter("authLogin");
    System.out.println(authLogin);
    if(username.equals("冯朗")&&password.equals("fenglang")){
        //对中文张三进行编码
        String username_code= URLEncoder.encode(username, "UTF-8");
        User user=new User();
        user.setUsername(username);
        user.setPassword(password);
        request.getSession().setAttribute("user",user);
        //用户登录成功,并且点击保存用户名密码;
        if(authLogin!=null){
            Cookie cookie_username = new Cookie("cookie_username",username_code);
            Cookie cookie_password = new Cookie("cookie_password",password);
            //设置cookie的持久化时间
            cookie_username.setMaxAge(60*60);
            cookie_password.setMaxAge(60*60);
            //设置cookie的携带路径
            cookie_username.setPath(request.getContextPath());
            cookie_password.setPath(request.getContextPath());
            //发送cookie
            response.addCookie(cookie_username);
            response.addCookie(cookie_password);
        }
        //登录成功,进入主页面;
        response.sendRedirect("home");
    }else{
        //用户名或者密码错误,返回登录页面;
        request.setAttribute("error","用户名或者密码错误");
        request.getRequestDispatcher("/index.jsp").forward(request,response);
    }
}
  • 自定义自动登录过滤器,如果有相应的cookie,并且经过数据库验证成功,则在session中保存当前的用户信息,自动放行
@Override
public void doFilter(ServletRequest request, ServletResponse response,
        FilterChain chain) throws IOException, ServletException {
    HttpServletRequest req=(HttpServletRequest) request;
    HttpSession session = req.getSession();

    //获得cookie中用户名和密码 进行登录的操作
    //定义cookie_username
    String cookie_username = null;
    //定义cookie_password
    String cookie_password = null;
    Cookie[] cookies = req.getCookies();
    if(cookies!=null&&cookies.length>0){
        for(Cookie cookie : cookies){
            //获得名字是cookie_username和cookie_password
            if("cookie_username".equals(cookie.getName())){
                cookie_username = cookie.getValue();
                //恢复中文用户名
                cookie_username = URLDecoder.decode(cookie_username, "UTF-8");
            }
            if("cookie_password".equals(cookie.getName())){
                cookie_password = cookie.getValue();
            }
        }
    }

    if(cookie_username!=null&&cookie_password!=null){
        if(cookie_username.equals("冯朗")&&cookie_password.equals("fenglang")){
            User user=new User();
            user.setUsername(cookie_username);
            user.setPassword(cookie_password);
            session.setAttribute("user",user);
        }
    }
    chain.doFilter(req, response);
}

发表评论

电子邮件地址不会被公开。 必填项已用*标注

昵称 *