基于JavaWeb的旅游项目--登录功能(带验证码)





登录功能

1、登录功能分析

在这里插入图片描述

2、基础代码编写

  • User.java(src\main\java\domain\User.java)
public class User {
    
    
    private int uid;
    private String username;
    private String password;
    private Date birthday;
    private String name;
    private String sex;
    private String telephone;
    private String email;
    private char status;
    private String code;
    }
  • TestUserService测试类(src\test\java\service\TestUserService.java)
//测试
public class TestUserService {
    
    
    @Test
    public void test01() {
    
    
        //将用户输入账号与密码发到后台
        UserService userService = new UserService();
        //1:查找用户数据
        User user = userService.findUserByName("jackhello");
        //2:根据数据, 正确,错误,不存在。
        if (user == null) {
    
    
            System.out.println("不存在");
        } else {
    
    
            //1:3种情况
            System.out.println("存在");
        }
    }

    @Test
    public void test02() {
    
    
        //将用户输入账号与密码发到后台
        UserService userService = new UserService();
        //1:查找用户数据
        User user = new User();
        user.setUsername("jackhello");
        user.setPassword("123456");
        user.setStatus('Y');
        int code = userService.login(user);
        //2:根据数据, 正确,错误,不存在。
        System.out.println(code);
    }
}
  • 编写UserDao方法(src\main\java\dao\UserDao.java)
public interface UserDao {
    
    
    //select * from tab_user where username = 'jackhello'
    User findByName(String name);
}
  • UserDao测试(src\test\java\dao\UserDaoTest.java)
public class UserDaoTest {
    
    

//    @Before:用来初始化@Test方法要使用到的资源
//    @After:用来释放资源
    // @Before ->@Test -> @After
    private SqlSession session;
    private  UserDao userDao;
    @Before
    public void init() throws Exception {
    
    
        System.out.println("Before");
        //创建Session对象
         session = MySessionUtils.getSession();
         userDao = session.getMapper(UserDao.class);
    }

    @After
    public void destory() throws Exception {
    
    
        System.out.println("After");

        //提交与关闭session
        session.commit();
        session.close();
    }

    @Test
    public void test01() {
    
    
      //查找对象
        User user = userDao.findByName("jackhello");
     //查看对象
        System.out.println(user);

    }
    @Test
    public void test02() {
    
    
        User user = userDao.findByName("jackhello");
        //查看对象
        System.out.println(user);

    }
}
  • UderDao.xml
<mapper namespace="com.smp.dao.UserDao">
    <select id="findByName" parameterType="string" resultType="user">
        select * from tab_user where username = #{
    
    username}
    </select>
</mapper>
  • SalMapConfig.xml
<configuration>
    <typeAliases>
        <package name="com.smp.domain"/>
    </typeAliases>

    <environments default="mybatis">
        <environment id="mybatis">

            <transactionManager type="JDBC"/>

            <dataSource type="POOLED">
                <!--    四大信息 -->
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/lvyou?characterEncoding=utf-8"/>
                <property name="username" value="root"/>
                <property name="password" value="123456"/>
            </dataSource>
        </environment>
    </environments>
<!--   一个mapper标签可以指定一个映射文件-->
    <mappers>
        <mapper resource="UserDao.xml"/>
    </mappers>
</configuration>
  • UserService的login方法
public class UserService {
    
    
    //直接获取Dao

    public User findUserByName(String name) {
    
    
        //getMapper是mybatis,给接口生成实现类,将实现类对象返回
        UserDao userDao = MySessionUtils2.getSession().getMapper(UserDao.class);
        //根据用户名查找用户
        User user = userDao.findByName(name);
        MySessionUtils2.getSession().commit();
        return user;
    }

    public int login(User user) {
    
    
        //账号密码
        UserDao userDao = MySessionUtils2.getSession().getMapper(UserDao.class);
        User u = userDao.findByName(user.getUsername());
        //比对数据库的账号密码
        if (u == null) {
    
    
            return -1;//找不到jack
        } else {
    
    
            //判断是否是激活的账户
            if ('Y'== u.getStatus()) {
    
    
                //是激活用户
                if (u.getUsername().equals(user.getUsername()) && u.getPassword().equals(user.getPassword())) {
    
    
                    return 1;//提示登录成功
                } else {
    
    
                    return -2;//账号或者密码出错
                }
            } else {
    
    
                return -3;//已激活
            }
        }
    }
}

3、ThreadLocal介绍

  • (1)在实际开发中,SqlSession属于Dao层代码,不允许出现在Service层中
    删除Mybastis依赖
  • (2)ThreadLocal是什么?
    java.lang.ThreadLocal 该类提供了线程局部 (thread-local) 变量,用于在当前线程中共享数据。
  • (3)有什么特点?
    》1 ThreadLocal工具类底层就是一个Map,key存放的当前线程,value存放需要共享的数据。
    》2 使用哪个线程存的,就只能使用哪个线程取

ThreadLocal改造MySessionUtils
(src\main\java\util\MySessionUtils2.java)

public class MySessionUtils2 {
    
    
    private static SqlSessionFactory sessionFactory;
    //static 静态代码,在类加载的时候执行一次,且只执行一次
    static{
    
    
//  》1 创建SqlSessionFactoryBuilder对象
        SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
// 》2 创建SqlSessionFactory对象
        InputStream inputStream = MySessionUtils2.class.getClassLoader().getResourceAsStream("SqlMapConfig.xml");
        sessionFactory = sqlSessionFactoryBuilder.build(inputStream);//加载核心配置文件 参1 输入流
//        》3 加载SqlMapConfig.xml配置文件
    }

    //A: 定义一个ThreadLocal集合,本质是Map<Thread,Object> map
    private   static ThreadLocal<SqlSession> map = new ThreadLocal<SqlSession>();

    public static SqlSession getSession() {
    
    

        //查找在local中,是否有对应的SqlSession
        SqlSession sqlSession = map.get(); //map.get(Thread.currentThread())

        if (sqlSession != null) {
    
    
            //有就直接返回给调用者使用
            return sqlSession;
        } else {
    
    

            //没有就创建一个新的,并且保存在local
            sqlSession = sessionFactory.openSession();
            //保存
            map.set(sqlSession);

            return sqlSession;
        }
    }

    public static void commitAndClose() {
    
    
        //将来进行写操作,之后需要提交,我们定义的方法
        SqlSession session = map.get();
        if (session != null) {
    
    
            session.commit();//提交
            session.close();//释放
            //已经关闭的session不能留在local
            //所以要删除
            map.remove();
        }
    }

    public static void rollbackAndClose() {
    
    
        //将来进行写操作,之后需要提交,我们定义的方法
        SqlSession session = map.get();
        if (session != null) {
    
    
            session.rollback();//回滚
            session.close();//释放
            //已经关闭的session不能留在local
            //所以要删除
            map.remove();
        }
    }
}

4、登录前台-表单校验1

  • (1)校验用户名 /^\w{8,20}$/ 单词字符,长度8到20位
  • (2)校验密码 /^\w{8,20}$/ 单词字符,长度8到20位
  • (3)校验密码邮箱 = /^\w+@\w+.\w+$/ 邮箱 [email protected]
  • 正则表达式
	正则表达式.test(字符串)
返回一个布尔值
	true 格式正确
	false 格式错误
  • login.jsp
<script type="text/javascript" >
        function checkUserName(){
    
    
            //获取输入框的值
            var username = $("#username").val();

            //正则表达式  定义一个规则,执行test方法,符合规则返回true,否则返回false

            var reg =  /^\w{
    
    8,20}$/ ;

            var flag = reg.test(username); //判断

            //如果符合要求,设置输入框边框是正常,否则设置红色

            if(flag){
    
    
                $("#username").css("border","");
            }else{
    
    
                $("#username").css("border","1px solid red");
            }
            //alert(flag)
            return flag;
        }

        function checkPassword(){
    
    
            //判断密码输入框的值是否合法
            var username = $("#password").val();
            var reg =  /^\w{
    
    8,20}$/ ;

            var flag = reg.test(username); //判断
            if(flag){
    
    
                $("#password").css("border","");//无色框
            }else{
    
    
                $("#password").css("border","1px solid red");//红框
            }
            //alert(flag)
            return flag;
        }
       
        })



    </script>

5、登录前台-表单校验2

  • submit函数
    控制表单是否提交,函数返回true,表单提交,返回false表单不提交
    此处
    在ajax提交,则写false
    页面是一个带有submit按钮的form表单 ,可以拦截

使用jquery编写 ajax请求

  • login.jsp
$("#btn_login").click(function () {
    
    
                //要求两个值正确,我们才做提交
                if(checkUserName()&&checkPassword()){
    
    
                    var un = $("#username").val()
                    var pw = $("#password").val()
                    //alert(un+pw)
                    //写提交
                    $.ajax({
    
    
                        url:"loginServlet",
                        async:true,
                        data:"username="+un+"&password="+pw,
                        type:"post",
                        dataType:"json",
                        success:function (data) {
    
    
                           // alert(data)  {"code":1,"data":"登录成功"}
                            if(1 == data.code){
    
    
                                //跳转到主页 index.html
                                $("#errorMsg").html("");
                                window.location="index.html"
                            }else{
    
    
                                //显示在界面上
                                $("#errorMsg").html(data.data);
                            }
                        },
                        error:function () {
    
    
                            alert("服务器发生了错误")
                        }
                    });
                }

6、登录后台_Servlet代码实现

  • (1)Servlet只做三件事
    》接收请求获取参数
    》处理参数
    》将结果响应给浏览器

  • LoginServlet.java

@WebServlet("/loginServlet")
public class LoginServlet extends HttpServlet {
    
    
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    
    
        doGet(request,response);
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    
    
        //获取请求参数
        Map<String, String[]> map = request.getParameterMap();
        User u = new User();
        try {
    
    
            //参1 javaBean 参2 map
            BeanUtils.populate(u,map);//将map里面所有的参数赋值给javaBean
        } catch (IllegalAccessException e) {
    
    
            e.printStackTrace();
        } catch (InvocationTargetException e) {
    
    
            e.printStackTrace();
        }
        //处理参数
        UserService userService = new UserService();
        int code = userService.login(u);
        //响应给浏览器 ajax 是响应json给浏览器就可以
        ResponseInfo info = new ResponseInfo();
        info.setCode(code);
        if(code == - 1){
    
    
            info.setData("用户不存在");
        }else  if(code ==  1){
    
    
            info.setData("登录成功");
        }else  if(code ==  -2){
    
    
            info.setData("账号密码出错");
        }else  if(code ==  -3){
    
    
            info.setData("账号未激活");
        }
        //转成json
        String json =new ObjectMapper().writeValueAsString(info);
        response.getWriter().println(json);
    }
}

7、过滤器

防止中文出现乱码
(src\main\java\web\filter\CharchaterFilter.java)

@WebFilter("/*")
public class CharchaterFilter implements Filter {
    
    
    public void init(FilterConfig filterConfig) throws ServletException {
    
    
    }

    public void doFilter(ServletRequest req, ServletResponse rep, FilterChain filterChain) throws IOException, ServletException {
    
    

        req.setCharacterEncoding("utf-8");
        // 处理响应乱码
        rep.setContentType("text/html;charset=utf-8");
        // 放行请求
        filterChain.doFilter(req,rep);
    }

    public void destroy() {
    
    

    }
}

8、改进登录功能

(1)MySessionUtils改进

  • A依赖B,移除B,A报错,耦合

(com\wzx\util\MySessionUtils2.java)

 public static <T> T getMapper(Class clz) {
    
    
       return (T) getSession().getMapper(clz);
    }
  • include标签
    include指令 include指令用于在本JSP中引入其他JSP页面。
    <%@ include file="relativeURI"%>
    <jsp:include page="header.jsp"/>
<!--引入尾部-->
<div id="footer">
    <%@include file="footer.jsp"%>
</div>

9、登录_欢迎信息提示

在这里插入图片描述

  • LoginServlet.java(src\main\java\web)
if(code ==  1){
    
    
            info.setData("登录成功");

            //查找出用户数据
            User user = userService.findUserByName(u.getUsername());
            //保存到session中
            request.getSession().setAttribute("user",user);
  • header.jsp
<!-- 登录状态  -->
        <div class="login">
            <%--             将session中的用户数据取出来 --%>
            <%--            判断用户对象是否为空  如果是提示请登录,否则显示用户信息--%>
            <c:if test="${user != null}">
                <span>欢迎回来,${
    
    user.name}</span>
            </c:if>
            <c:if test="${user == null}">
                <span>您未登录,请登录</span>
            </c:if>
            <a href="myfavorite.html" class="collection">我的收藏</a>
            <a href="${pageContext.request.contextPath}/loginOutServlet">退出</a>
        </div>

10、退出功能

  • header.jsp
<a href="${pageContext.request.contextPath}/loginOutServlet">退出</a>
  • LoginOutServlet.java(src\main\java\web)
@WebServlet("/loginOutServlet")
public class LoginOutServlet extends HttpServlet {
    
    
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    
    
            doGet(request,response);
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    
    
         //查找session
        HttpSession session = request.getSession();
        //让session销毁或者过期
        session.invalidate();
         //重定向 login.jsp
        response.sendRedirect(request.getContextPath()+"/login.jsp");
    }
}

11、验证码功能

  • 验证码流程
    后台程序ASevlet产生随机字符 code1
    随机字符保存在session中 code1
    随机字符再转成图片响应给img标签
    当用户提交表单时也同时提交输入的验证码 code2
    后台程序B比较两个随机字符串是否相等,不相等则验证码出错。

  • login.jsp

<div class="verify">
                    <input name="check" type="text" placeholder="请输入验证码" autocomplete="off">
                    <span><img src="checkCode" alt="" onclick="changeCheckCode(this)"></span>
                    <script type="text/javascript">
                        //图片点击事件
                        function changeCheckCode(img) {
    
    
                            img.src="checkCode?"+new Date().getTime();
                        }
                    </script>
  • LoginServlet.java((src\main\java\web)
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    
    

        //从请求中获取check1码
        String check1 = request.getParameter("check");
        //从session中获取check2码
        String check2 = (String) request.getSession().getAttribute("CHECKCODE_SERVER");
        System.out.println(check1);
        System.out.println(check2);
        //从session中删除check2码
        request.getSession().removeAttribute("CHECKCODE_SERVER");
        //比较check1 与 check2
        //相同表示验证码不正确,将提示信息写到页面的错误提示
        if(check1 == null || !check1.equalsIgnoreCase(check2)){
    
    
            //验证码不看大小写
            ResponseInfo responseInfo = new ResponseInfo();
            responseInfo.setCode(-4);
            responseInfo.setData("登录失败,验证码出错");

            //json
            String json = new ObjectMapper().writeValueAsString(responseInfo);
            response.getWriter().println(json);
            return;
        }
  • CheckCodeServlet.java((src\main\java\web)
@WebServlet("/checkCode")
public class CheckCodeServlet extends HttpServlet {
    
    
	public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {
    
    
		
		//服务器通知浏览器不要缓存
		response.setHeader("pragma","no-cache");
		response.setHeader("cache-control","no-cache");
		response.setHeader("expires","0");
		
		//在内存中创建一个长80,宽30的图片,默认黑色背景
		//参数一:长
		//参数二:宽
		//参数三:颜色
		int width = 80;
		int height = 30;
		BufferedImage image = new BufferedImage(width,height,BufferedImage.TYPE_INT_RGB);
		
		//获取画笔
		Graphics g = image.getGraphics();
		//设置画笔颜色为灰色
		g.setColor(Color.GRAY);
		//填充图片
		g.fillRect(0,0, width,height);
		
		//产生4个随机验证码,12Ey
		String checkCode = getCheckCode();
		//将验证码放入HttpSession中
		request.getSession().setAttribute("CHECKCODE_SERVER",checkCode);
		
		//设置画笔颜色为黄色
		g.setColor(Color.YELLOW);
		//设置字体的小大
		g.setFont(new Font("黑体",Font.BOLD,24));
		//向图片上写入验证码
		g.drawString(checkCode,15,25);
		
		//将内存中的图片输出到浏览器
		//参数一:图片对象
		//参数二:图片的格式,如PNG,JPG,GIF
		//参数三:图片输出到哪里去
		ImageIO.write(image,"PNG",response.getOutputStream());
	}
	/**
	 * 产生4位随机字符串 
	 */
	private String getCheckCode() {
    
    
		String base = "0123456789ABCDEFGabcdefg";
		int size = base.length();
		Random r = new Random();
		StringBuffer sb = new StringBuffer();
		for(int i=1;i<=4;i++){
    
    
			//产生0到size-1的随机值
			int index = r.nextInt(size);
			//在base字符串中获取下标为index的字符
			char c = base.charAt(index);
			//将c放入到StringBuffer中去
			sb.append(c);
		}
		return sb.toString();
	}
	public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    
    
		this.doGet(request,response);
	}
}

猜你喜欢

转载自blog.csdn.net/qq_41209886/article/details/108872496