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);
}