目录
2.然后我们实现service层,要明白service与dao层的区别,它是根据具体业务实现:
1.盐值;2.DigestUtils.md5DigestAsHex(xxx.getBytes());
拦截器实现思路:1.实现HandlerInterceptor 2.利用preHandle()方法进行拦截
1.首先我们先写好dao与mapper
UserDao:
package com.yanzhen.dao;
import java.util.List;
import java.util.Map;
import com.yanzhen.entity.User;
public interface UserDao {
public int create(User pi);
public int delete(Map<String, Object> paramMap);
public int update(Map<String, Object> paramMap);
public List<User> query(Map<String, Object> paramMap);
public User detail(Map<String, Object> paramMap);
public int count(Map<String, Object> paramMap);
}
UserMaper
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.yanzhen.dao.UserDao">
<resultMap type="com.yanzhen.entity.User" id="User">
<id column="id" property="id"/>
<result column="id" property="id"/>
<result column="name" property="name"/>
<result column="remark" property="remark"/>
<result column="user_name" property="userName"/>
<result column="user_pwd" property="userPwd"/>
</resultMap>
<insert id="create" keyProperty="id" useGeneratedKeys="true" parameterType="com.yanzhen.entity.User">
insert into tb_user(
name,
remark,
user_name,
user_pwd
)values(
#{name},
#{remark},
#{userName},
#{userPwd}
)
</insert>
<select id="query" resultMap="User">
select * from tb_user
<include refid="UserFindCriteria"/>
<if test="offset!=null and rows!=null">limit ${offset} , ${rows}</if>
</select>
<select id="count" resultType="int">
select count(1) from tb_user
<include refid="UserFindCriteria"/>
</select>
<select id="detail" resultMap="User">
select * from tb_user
<include refid="UserFindCriteria"/>
limit 1
</select>
<delete id="delete">
delete from tb_user
<include refid="UserFindCriteria"/>
</delete>
<update id="update">
update tb_user
<include refid="UserUpdateCriteria"/>
<include refid="UserFindCriteria"/>
</update>
<sql id="UserFindCriteria">
<where>
<if test="id != null">and id = #{id}</if>
<if test="name != null and name != ''">and name like concat('%',#{name},'%')</if>
<if test="remark != null and remark != ''">and remark = #{remark}</if>
<if test="userName != null and userName != ''">and user_name like concat('%',#{userName},'%')</if>
<if test="userPwd != null and userPwd != ''">and user_pwd = #{userPwd}</if>
</where>
</sql>
<sql id="UserUpdateCriteria">
<set>
<if test="updateId != null">id = #{updateId},</if>
<if test="updateName != null and updateName != ''">name = #{updateName},</if>
<if test="updateRemark != null and updateRemark != ''">remark = #{updateRemark},</if>
<if test="updateUserName != null and updateUserName != ''">user_name = #{updateUserName},</if>
<if test="updateUserPwd != null and updateUserPwd != ''">user_pwd = #{updateUserPwd},</if>
</set>
</sql>
</mapper>
2.然后我们实现service层,要明白service与dao层的区别,它是根据具体业务实现:
比如说登录,我们service层首先将userName与userPwd放入map容器中并返回map容器
然后dao层调用查询单个用户的方法(参数都为map),所以userName与userPwd需要放入map中
package com.yanzhen.service;
import com.yanzhen.dao.UserDao;
import com.yanzhen.entity.User;
import com.yanzhen.entity.User;
import com.yanzhen.utils.BeanMapUtils;
import com.yanzhen.utils.MD5Utils;
import com.yanzhen.utils.MapParameter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Map;
@Service
public class UserService {
@Autowired
private UserDao userDao;
public int create(User pi) {
pi.setUserPwd(MD5Utils.getMD5(pi.getUserPwd()));
return userDao.create(pi);
}
public int delete(Integer id) {
return userDao.delete(MapParameter.getInstance().addId(id).getMap());
}
public int delete(String ids) {
int flag = 0;
for (String str : ids.split(",")) {
flag = userDao.delete(MapParameter.getInstance().addId(Integer.parseInt(str)).getMap());
}
return flag;
}
public int update(User user) {
Map<String, Object> map = MapParameter.getInstance().add(BeanMapUtils.beanToMapForUpdate(user)).addId(user.getId()).getMap();
return userDao.update(map);
}
public List<User> query(User user) {
return userDao.query(BeanMapUtils.beanToMap(user));
}
public User detail(Integer id) {
return userDao.detail(MapParameter.getInstance().addId(id).getMap());
}
public int count(User user) {
return userDao.count(BeanMapUtils.beanToMap(user));
}
public User login(String userName,String password){
Map<String, Object> map = MapParameter.getInstance()
.add("userName", userName)
.add("userPwd", password)
.getMap();//将用户信息放入map容器中
return userDao.detail(map);//根据map信息在mapper中的sql语句中进行查询,返回用户
}
}
因为我们这个项目是有三种登录方式,所以学生以及老师也要各自实现自己login方法,反正都是根据用户名以及密码查询用户,就不具体演示了
3.Controller层:调用后台的业务逻辑,并且返回数据给到前端jsp页面上,可以理解为最终的实现层,也是与数据交接的地方;(一般来说,Controller层获取的数是由前端jquery实现ajax获取前台数据给到对应controller的)
思路:1.参数为用户名及密码,登录类型,验证码,session;2.进行错误验证(比如说用户名密码为空的情况);3.根据type具体类型为多少来实现不同的登录方式;4.登录方式的实现(验证session)
package com.yanzhen.controller;
import com.yanzhen.entity.Student;
import com.yanzhen.entity.Teacher;
import com.yanzhen.entity.User;
import com.yanzhen.service.StudentService;
import com.yanzhen.service.TeacherService;
import com.yanzhen.service.UserService;
import com.yanzhen.utils.Code;
import com.yanzhen.utils.MD5Utils;
import com.yanzhen.utils.MapControll;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.servlet.http.HttpSession;
import java.util.Map;
@Controller
public class LoginController {
@Autowired
private UserService userService;
@Autowired
private StudentService studentService;
@Autowired
private TeacherService teacherService;
@GetMapping("/login")
public String login(){
return "login";
}
@PostMapping("/login")
@ResponseBody
public Map<String,Object> login(String userName, String password, String type,String captcha, HttpSession session){
if(StringUtils.isEmpty(userName) || StringUtils.isEmpty(password) || StringUtils.isEmpty(type)){
return MapControll.getInstance().error("用户名或密码不能为空").getMap();
}
String _captcha = (String)session.getAttribute("captcha");
if(StringUtils.isEmpty(captcha)){
return MapControll.getInstance().error("验证码不能为空").getMap();
}
if(!captcha.equals(_captcha)){
return MapControll.getInstance().error("验证码错误").getMap();
}
//管理员登录
if("1".equals(type)){
User user = userService.login(userName, MD5Utils.getMD5(password));
if(user != null){
//此时user的业务层返回了用户,然后我们将这些用户放入session中
session.setAttribute("user",user);
session.setAttribute("type",1);
return MapControll.getInstance().success().add("data",user).getMap();
}else{
return MapControll.getInstance().error("用户名或密码错误").getMap();
}
}
//老师登录
if("2".equals(type)){
Teacher teacher = teacherService.login(userName, MD5Utils.getMD5(password));
if(teacher != null){
// 将用户信息放入session中,并且放入用户类型
session.setAttribute("user",teacher);
session.setAttribute("type",2);
//用户信息存在,将用户信息放入map容器中,并且放入成功提示信息,返回map容器,后给前端页面ajax中的data
return MapControll.getInstance().success().add("data",teacher).getMap();
}else{
return MapControll.getInstance().error("用户名或密码错误").getMap();
}
}
//学生登录
if("3".equals(type)){
Student student = studentService.login(userName, MD5Utils.getMD5(password));
if(student != null){
session.setAttribute("user",student);
session.setAttribute("type",3);
return MapControll.getInstance().success().add("data",student).getMap();
}else{
return MapControll.getInstance().error("用户名或密码错误").getMap();
}
}
return MapControll.getInstance().error("用户名或密码错误").getMap();
}
}
这里用StringUtils来验证userName、password、type、captcha是否为空,如果为空就返回错误,将错误信息放入map容器中(这里用了自定义工具类)
package com.yanzhen.utils;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class MapControll {
//目标对象
private Map<String,Object> paramMap = new HashMap<>();
//私有构造
private MapControll(){
}
public static MapControll getInstance(){
return new MapControll();
}
public MapControll add(String key, Object value){
paramMap.put(key,value);
return this;//this这里指的就是对象new MapController();
}
public MapControll success(){
paramMap.put("code",Code.SUCCESS.getCode());
paramMap.put("msg",Code.SUCCESS.getMsg());//msg为返回给前端的信息,作为验证,若为1000说明成功,则跳转到首页
return this;
}
public MapControll error(){
paramMap.put("code",Code.ERROR.getCode());
paramMap.put("msg",Code.ERROR.getMsg());
return this;
}
public MapControll error(String msg){
paramMap.put("code",Code.ERROR.getCode());
paramMap.put("msg",msg);
return this;
}
public MapControll notEmpty(){
paramMap.put("code",Code.NOT_EMPTY.getCode());
paramMap.put("msg",Code.NOT_EMPTY.getMsg());
return this;
}
public MapControll nodata(){
paramMap.put("code",Code.NODATA.getCode());
paramMap.put("msg",Code.NODATA.getMsg());
return this;
}
public MapControll page(List<?> list,Integer count){
paramMap.put("data",list);
paramMap.put("count",count);
return this;
}
public MapControll put(String key, Object value){
this.add(key,value);
return this;
}
public MapControll addId(Object value){
paramMap.put("id",value);
return this;
}
public MapControll add(Map<String,Object> map){
for (Map.Entry<String, Object> entry : map.entrySet()) {
paramMap.put(entry.getKey(),entry.getValue());
}
return this;
}
public MapControll put(Map<String,Object> map){
return this.add(map);
}
public Map<String,Object> getMap(){
return paramMap;
}
}
至于具体管理员学生老师登录:1.根据类型判断;2.调用业务层方法获取用户;3.如果用户不为空放入session中,type也要放入,然后将用户信息放入map容器中,且调用success得到正确码给,并且返回map容器,将返回数据给到前端验证
4.这里的验证方式是通过ajax来实现的
// 进行登录操作 form.on('submit(login)', function (data) { $.ajax({ url:"${basePath}login", type:"POST", dataType:'json', data:data.field, success:function(data){ if(data.code == "1000"){ location.href = "index"; }else{ //登录失败显示出后端返回给前端的数据 layer.msg(data.msg,{time:2000}); } } }); return false; });
最重要的三个点:1.url:对应着controller ;2.data:给对应controller传去的数据 ; 3.success:来自后台controller回显的数据,这里起了一个验证效果;
5.工具类:MD5Utils
1.盐值;2.DigestUtils.md5DigestAsHex(xxx.getBytes());
package com.yanzhen.utils; import org.springframework.util.DigestUtils; public class MD5Utils { //盐 private static final String salt = "StudentSystemManager###$$@@"; public static String getMD5(String string){ String val = string+salt; return DigestUtils.md5DigestAsHex(val.getBytes()); } public static void main(String[] args) { System.out.println(getMD5("123456")); } }
6.拦截器的实现:只有登录的用户才有资格访问
拦截器实现思路:1.实现HandlerInterceptor 2.利用preHandle()方法进行拦截
3.req.getSession(),如果session中为空则抛出异常(自定义异常),否则通过
package com.yanzhen.utils; import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.ModelAndView; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; public class PermissionInterceptor implements HandlerInterceptor { //可以根据session中是否有信息进行拦截 @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { HttpSession session = request.getSession(); // 如果session中user信息不为空,则放行,否则抛出异常并且传入message提示 if(session.getAttribute("user") != null){ return true; }else{ throw new PermissionException("没有权限访问"); } } }
自定义异常:继承运行异常,当异常出现,可以自定义异常所报出的信息
package com.yanzhen.utils; public class PermissionException extends RuntimeException { //自定义异常 public PermissionException(String message) { super(message); } }
但是我们还需要处理异常,因为你如果没有权限而去访问就会报出405,所以我们要有一个全局异常处理,这样我们就可以返回一个error页面或者返回json,相对来说比较友好
package com.yanzhen.utils; import org.springframework.stereotype.Controller; import org.springframework.ui.ModelMap; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.servlet.ModelAndView; import javax.jws.HandlerChain; import java.util.Map; @ControllerAdvice public class GlobalControllerAdvice { //全局异常处理 private final String ERROR = "error"; //设定全局处理的异常 @ExceptionHandler(value=PermissionException.class) public ModelAndView noPermission(PermissionException e){ //new一个返回页面为error ModelAndView modelAndView = new ModelAndView(ERROR); //绑定:将异常中的message信息与error页面绑定,也就是说当抛出PermissionException异常时,就返回error页面 modelAndView.addObject(ERROR,e.getMessage()); return modelAndView; } @ExceptionHandler(value=RuntimeException.class) @ResponseBody public Map<String,Object> runtimeException(RuntimeException e){ e.printStackTrace(); return MapControll.getInstance().error().getMap(); } }
7.配置文件
1.首先是web.xml
三步骤:1.前端控制器DispatcherServlet(注意里面初始化加载的spring-mvc.xml);
2.配置web.xml配置文件的节点<context-param>:当你启动项目时,容器就会读取它,并将Context-param中的给到servletContext上下文,并且会读取listener对上下文进行监听
3.配置过滤器filter
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" version="4.0"> <!-- 整合spring 1.前端控制器,为了加载spring-mvc和容器 2.配置spring上下文监听器,加载spring容器 3.编码过滤器--> <servlet> <servlet-name>student_system</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:spring-mvc.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>student_system</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> <!--上下文参数--> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:applicationContext.xml</param-value> </context-param> <!-- 配置spring容器上下文监听,ContextLoader里面有ContextConfigLocation属性,然后会被servlet调用--> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <!--编码过滤--> <filter> <filter-name>encodingFilter</filter-name> <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class> <init-param> <param-name>encoding</param-name> <param-value>utf-8</param-value> </init-param> </filter> <filter-mapping> <filter-name>encodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <!-- <welcome-file-list>--> <!-- <welcome-file>index.jsp</welcome-file>--> <!-- </welcome-file-list>--> </web-app>
2.application.xml配置
我们这里就不多配置一个spring-service.xml了(这种配置方式狂神视频中有),我们直接全部放在application.xml中;
1.首先是扫描service,扫描其注解(类似这种文件形式的都是<context:xxx>)
<context:component-scan base-package="com.yanzhen.service" />
2.配置数据库配置文件位置与数据源驱动参数
<context:property-placeholder location="classpath:db.properties" /> <bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource"> <property name="driverClassName" value="${jdbc.driver}"></property> <property name="url" value="${jdbc.url}"></property> <property name="username" value="${jdbc.username}"></property> <property name="password" value="${jdbc.password}"></property> </bean>
3.配置sqlSessionFactory(因为是由sqlSessionFactoryBuilder读取mybatis配置文件而得到的关键对象,可以理解为sqlSessionFactory是mybatis的核心,是它配置文件的实例,里面所有的sql操作):里面要注入数据源驱动参数,mybatis配置文件,并且扫描所有的mapper
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="dataSource" ref="dataSource"/> <property name="configLocation" value="classpath:mybatis-config.xml"></property> <property name="mapperLocations"> <list> <value>classpath:com/yanzhen/dao/*.xml</value> </list> </property> <!--配置分页插件--> <property name="plugins"> <array> <bean class="com.github.pagehelper.PageInterceptor"> <property name="properties"> <value> helperDialect=mysql </value> </property> </bean> </array> </property> </bean>
像在xml中对bean中属性进行赋值一般有两种方式:1.ref:将其他bean作为属性值引入;2.value:除了能将其他bean作为属性值引入之外,还能引入路径
4.MapperScannerConfigurer的配置,作用类似于sqlSessionTemplate的配置
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <property name="basePackage" value="com.yanzhen.dao"></property> <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"></property> </bean>
3.spring-mvc.xml配置
1.mvc一般是和controller接轨的,因为controller和前端页面有关系,所以要扫描controller以及utils下的文件
<context:component-scan base-package="com.yanzhen.controller,com.yanzhen.utils" />
2.因为web.xml中配置了前端控制器Dispatcher,所以这里要配置一个<mvc:annotation-driven>,作用:注解驱动,能够自动注册@RequestMappingHandlerMapping映射器以及@RequestMappingHandlerAdapter适配器;
映射器作用:controller中每个方法都对应着一个@RequestMapping,它的作用就是识别注解下的方法,根据注解定义的url与方法进行匹配,然后交给前端控制器;
适配器:方法与@RequestMapping进行适配;
<mvc:annotation-driven> <mvc:message-converters> <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"> <property name="objectMapper"> <bean class="com.fasterxml.jackson.databind.ObjectMapper"> <property name="dateFormat"> <bean class="java.text.SimpleDateFormat"> <constructor-arg type="java.lang.String" value="yyyy-MM-dd"/> </bean> </property> </bean> </property> </bean> </mvc:message-converters> </mvc:annotation-driven>
3.视图解析器配置:
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix" value="/WEB-INF/page/"></property> <property name="suffix" value=".jsp"></property> </bean>
4.拦截器配置:
<mvc:interceptors> <mvc:interceptor> <mvc:mapping path="/**/*"/> <bean class="com.yanzhen.utils.PathInterceptor" /> </mvc:interceptor> <mvc:interceptor> <mvc:mapping path="/**/*"/> <mvc:exclude-mapping path="/login"/> <mvc:exclude-mapping path="/logout"/> <!-- 这里是/captcha/*是因为后面只有一个子路径了--> <mvc:exclude-mapping path="/captcha/*"/> <!-- 后面还有多个文件--> <mvc:exclude-mapping path="/static/**"/> <bean class="com.yanzhen.utils.PermissionInterceptor"/> </mvc:interceptor> </mvc:interceptors>
想要所有源码关注联系我