发表于: 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还是有,但是还是比较欣慰,感觉自己有所进步.



返回列表 返回列表
评论

    分享到