发表于: 2018-01-10 21:53:34
1 869
今天完成的事情:
对任务5的代码进行了重构以及大部分注释的添加.
controller层没有逻辑相关的东西,仅仅为页面跳转服务.我增加了用户登陆之后显示用户名(其实应该是昵称)的功能,并做了退出按钮.(当然逻辑也是在service层实现)
package com.controller;
import com.bean.GoodStudent;
import com.bean.User;
import com.service.IGoodStudentService;
import com.service.IJobsService;
import com.service.UserServiceImpl;
import com.util.Encrypt;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.SessionAttributes;
import org.springframework.web.util.WebUtils;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.util.List;
/**
* @author Arike
* Create_at 2017/12/26 20:04
*/
@Controller
public class MyController {
@Autowired
IGoodStudentService goodStudentServiceImpl;
@Autowired
IJobsService jobsServiceImpl;
@Autowired
UserServiceImpl userServiceImpl;
Logger logger = Logger.getLogger(MyController.class);
/**
* 首页
* @param model 用于给页面使用的模型
* @return 返回tiles框架里的definition的name
*/
@RequestMapping(value = "/u/jnshu", method = RequestMethod.GET)
public String jnshu(ModelMap model) {
List<GoodStudent> list = goodStudentServiceImpl.selectAll();
model.addAttribute("list", list);
model.addAttribute("count", goodStudentServiceImpl.count());
model.addAttribute("countGood", goodStudentServiceImpl.countGood());
return "jnshu";
}
/**
* 职业列表
* @param model 用于返回给页面使用的模型
* @return 返回tiles框架里的definition的name
*/
@RequestMapping("/u/joblist")
public String job(ModelMap model) {
model.addAttribute("joblist", jobsServiceImpl.selectJobs());
return "joblist";
}
/**
* 关于页面
* @return 返回tiles框架里的definition的name(该页面没有动态资源)
*/
@RequestMapping("/u/cooperation")
public String cooperation() {
return "cooperation";
}
/**
* 登陆页面
* @return 返回login页面
*/
@RequestMapping(value = "/login", method = RequestMethod.GET)
public String login() {
return "login";
}
/**
* 登陆按钮的URL
* @param response 用于给与(响应)页面cookie使用
* @param session 用于记录与cookie验证的key/value以及记录用户的用户名用于页面显示
* @param model 返回给页面使用显示账密错误情况
* @param user 接收用户输入的账户名以及密码用于验证登陆
* @return
*/
@RequestMapping(value = "/loginPage", method = RequestMethod.POST)
public String checkLogin(HttpServletResponse response, HttpSession session, ModelMap model, User user) {
if (userServiceImpl.checkLogin(user,response,session)) {
return "redirect:/u/jnshu";
} else {
model.addAttribute("intro", "用户名或密码错误,请重新登陆");
return "redirect:/login";
}
}
/**
*
* @param request 用以获取cookie和session对象,并清除cookie以及session的值.
* @return
*/
@RequestMapping(value = "/loginOut", method = RequestMethod.GET)
public String delCookie(HttpServletRequest request) {
// WebUtils.getCookie(request, "key").setValue(null);
request.getSession().invalidate();
return "redirect:/login";
}
/**
* 注册按钮的URL
* @param user 接收用户填写的注册信息
* @return
*/
@RequestMapping(value = "/regUser", method = RequestMethod.POST)
public String regUser(User user,ModelMap model) {
userServiceImpl.insertUser(user,model);
return "regUser";
}
}
service负责了所有的逻辑运算以及判断,cookie和Session的存活周期我都设置为了1天.(这里有个问题了,session不给生命周期,服务器是没什么压力的,客户端关闭session就消失,设置了持续时间服务器内存就得承受一天的压力,后期话的可能缓存能解决这个问题.)
package com.service;
import com.bean.User;
import com.dao.UserDao;
import com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException;
import com.util.Encrypt;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.ui.Model;
import org.springframework.ui.ModelMap;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
/**
* @author Arike
* Create_at 2018/1/6 15:45
*/
@Service
public class UserServiceImpl implements IUserService {
@Autowired
UserDao userDao;
/**
* 注册用户的方法
* @param user 页面传回来的数据
*/
@Override
public void insertUser(User user , ModelMap model) {
user.setCreateAt(System.currentTimeMillis());
String salt = Encrypt.getSalt();
String encode = user.getPassWord() + salt;
encode = Encrypt.getSHA256Str(encode);
user.setSalt(salt);
user.setPassWord(encode);
try {
userDao.insertUser(user);
} catch (Exception e) {
model.addAttribute("intro","用户名已存在");
}
}
/**
* 下面2个方法都为验证登陆服务
* @param user 用户登陆是填写的数据
* @return 返回根据用户填写的用户名查询的结果,无值的话返回的是null
*/
@Override
public User loginSelect(User user) {
return userDao.loginSelect(user);
}
/**
* 验证用户输入的密码是否和数据库中的密码相同
* @param user 用户登陆填写的数据
* @param args 接收更多的用以操作的参数, request,response
* @return 返回值为一个boolean值给controller,用于判断跳转的页面
*/
public boolean checkLogin(User user, Object... args) {
User selectUser = loginSelect(user);
if (selectUser == null) {
return false;
} else {
String checkEocode = Encrypt.getSHA256Str(user.getPassWord() + selectUser.getSalt());
if (checkEocode.equals(selectUser.getPassWord())) {
HttpServletResponse response = (HttpServletResponse) args[0];
HttpSession session = (HttpSession) args[1];
String code = Encrypt.getSHA256Str(Encrypt.getSalt()).toUpperCase();
Cookie cookie = new Cookie("key", code);
cookie.setMaxAge(60 * 60 * 24);
cookie.setPath("/");
response.addCookie(cookie);
session.setAttribute("key", code);
session.setMaxInactiveInterval(60 * 60 * 24);
session.setAttribute("name", user.getUserName());
return true;
} else {
return false;
}
}
}
}
另外贴上加密工具类Encrypt,一个是用以加密操作的工具类,提供了盐值获取,SHA512算法加密,转换为16进制字符串的方法.
package com.util;
import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
/**
* @author Arike
* Create_at 2018/1/8 11:10
* 该类用于密码加密和验证的操作
*/
public class Encrypt {
private Encrypt() { }
/**
* 将byte转为16进制
* @param bytes 传入加密了过后的byte密码
* @return 返回给加密方法操作的密码字符串
*/
public static String byte2Hex(byte[] bytes) {
StringBuffer stringBuffer = new StringBuffer();
String temp = null;
for (byte aByte : bytes) {
temp = Integer.toHexString(0Xff/*255*/ & aByte);//使用0Xff其实是使用1111 1111八个二进制位
if(temp.length()==1){ //但这里是作为int字面值来做的,所以他的二进制
// 得到只有1位的时候在后面补0 应该为0000 0000 0000 0000 0000 0000 1111 1111
stringBuffer.append("0"); //这样能保证byte为负数的时候去掉符号位.
}
stringBuffer.append(temp);
}
return stringBuffer.toString();
}
/**
*
* @return 返回一个盐值
*/
public static String getSalt(){
byte[] bytes =new byte[10];
SecureRandom sr = new SecureRandom();
sr.nextBytes(bytes);
return byte2Hex(bytes);
}
/**
* 利用java原生的摘要实现SHA256加密
* @param str 加密后的报文
* @return 存储到服务器的密码
*/
public static String getSHA256Str(String str){
MessageDigest messageDigest;
String encodeStr="";
try {
messageDigest= MessageDigest.getInstance("SHA-512");
messageDigest.update(str.getBytes("UTF-8"));
encodeStr=byte2Hex(messageDigest.digest());
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return encodeStr;
}
}
这是统计controller执行耗时的AOP类,切面
package com.util;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Component;
/**
* @author Arike
* Create_at 2017/12/28 15:42
*/
@Component
public class TimeCountUtil {
private Long begin;
Logger logger = Logger.getLogger(TimeCountUtil.class);
public void start(){
begin = System.currentTimeMillis();
}
public void end(){
logger.info("Controller执行耗时:"+(System.currentTimeMillis()-begin)+"毫秒");
}
}
<aop:config>
<aop:aspect ref="timeCountUtil">
<aop:pointcut id="controller" expression="execution(* com.controller.MyController.*(..))"/>
<aop:before method="start" pointcut-ref="controller"/>
<aop:after method="end" pointcut-ref="controller"/>
</aop:aspect>
</aop:config>
看一下最终效果图:
登录界面
登录后页面:
任务5的深度思考:
1.什么是session?什么是cookie?session和cookie有什么区别?什么场景适用于session?什么场景适用于cookie?
这几天看了很多关于Session和cookie的文章,心里大致对这2个东西有了一定的了解.
首先这2个都类似于Map集合,是键值对的形式存在的.以key对应value,cookie是保存在用户客户端的,而session存在于web容器里,
cookie在客户端我们能直接看到他的每一个key/vlaue,一个cookie就是一个key/value,而Session一次会话访问只会有一个,更像一个容器,里面可以存放不止一对的key/value值.
在我的任务里,session就用于了存放用户信息以及和cookie对应验证登陆的Value.完成了验证登陆和回显用户信息的功能.
cookie仅仅用于存放用户登陆状态
session可以做更多的事情.cookie就比较局限
以上仅是个人理解.
2.拦截器、过滤器、监听器各有什么作用?
过滤器
Servlet中的过滤器Filter是实现了javax.servlet.Filter接口的服务器端程序,主要的用途是过滤字符编码、做一些业务逻辑判断等。其工作原理是,只要你在web.xml文件配置好要拦截的客户端请求,它都会帮你拦截到请求,此时你就可以对请求或响应(Request、Response)统一设置编码,简化操作;同时还可以进行逻辑判断,如用户是否已经登录、有没有权限访问该页面等等工作,它是随你的web应用启动而启动的,只初始化一次,以后就可以拦截相关的请求,只有当你的web应用停止或重新部署的时候才能销毁。
监听器
Servlet的监听器Listener,它是实现了javax.servlet.ServletContextListener接口的服务器端程序,它也是随web应用的启动而启动,只初始化一次,随web应用的停止而销毁。主要作用是:做一些初始化的内容添加工作、设置一些基本的内容、比如一些参数或者是一些固定的对象等等。
拦截器
拦截器是在面向切面编程中应用的,就是在你的service或者一个方法前调用一个方法,或者在方法后调用一个方法比如动态代理就是拦截器的简单实现,在你调用方法前打印出字符串(或者做其它业务逻辑的操作),也可以在你调用方法后打印出字符串,甚至在你抛出异常的时候做业务逻辑的操作。拦截器不是在web.xml配置的,比如struts在struts.xml配置,在springMVC在spring与springMVC整合的配置文件中配置。
其实就任务而言, 过滤器(似乎也能完成拦截器能做的功能,但是我没用)和监听器在任务过程种感觉似乎不存在,因为都是一些配置定死了的东西,没有自己去重写,而拦截器才是由我们去开发逻辑的东西. 用户登录状态验证以及url是否符合规范进行url的通放行.很好的在AOP的基础上加强了他本身的功能.
明天计划的事情:(一定要写非常细致的内容)
开始任务6
遇到的问题:(遇到什么困难,怎么解决的)
样式是个好东西,打算学一波CSS了..
收获:(通过今天的学习,学到了什么知识)
自己做了一个简陋的登陆系统,虽然BUG还是有,但是还是比较欣慰,感觉自己有所进步.
评论