登陆页面总结(bootdo)

总结自开源项目bootdo

图标设置

验证码

 验证码生成工具类

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.util.Random;

/**
 * @author bootdo
 */
public class RandomValidateCodeUtil {


    public static final String RANDOMCODEKEY = "RANDOMVALIDATECODEKEY";//放到session中的key
    private String randString = "0123456789";//随机产生只有数字的字符串 private String
    //private String randString = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";//随机产生只有字母的字符串
    //private String randString = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";//随机产生数字与字母组合的字符串
    private int width = 95;// 图片宽
    private int height = 25;// 图片高
    private int lineSize = 40;// 干扰线数量
    private int stringNum = 4;// 随机产生字符数量

    private static final Logger logger = LoggerFactory.getLogger(RandomValidateCodeUtil.class);

    private Random random = new Random();

    /**
     * 获得字体
     */
    private Font getFont() {
        return new Font("Fixedsys", Font.CENTER_BASELINE, 18);
    }

    /**
     * 获得颜色
     */
    private Color getRandColor(int fc, int bc) {
        if (fc > 255) {
            fc = 255;
        }
        if (bc > 255) {
            bc = 255;
        }
        int r = fc + random.nextInt(bc - fc - 16);
        int g = fc + random.nextInt(bc - fc - 14);
        int b = fc + random.nextInt(bc - fc - 18);
        return new Color(r, g, b);
    }

    /**
     * 生成随机图片
     */
    public void getRandcode(HttpServletRequest request, HttpServletResponse response) {
        HttpSession session = request.getSession();
        // BufferedImage类是具有缓冲区的Image类,Image类是用于描述图像信息的类
        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_BGR);
        Graphics g = image.getGraphics();// 产生Image对象的Graphics对象,改对象可以在图像上进行各种绘制操作
        g.fillRect(0, 0, width, height);//图片大小
        g.setFont(new Font("Default", Font.ROMAN_BASELINE, 18));//字体大小
        g.setColor(getRandColor(110, 133));//字体颜色
        // 绘制干扰线
        for (int i = 0; i <= lineSize; i++) {
            drowLine(g);
        }
        // 绘制随机字符
        String randomString = "";
        for (int i = 1; i <= stringNum; i++) {
            randomString = drowString(g, randomString, i);
        }
        logger.info(randomString);
        //将生成的随机字符串保存到session中
        session.removeAttribute(RANDOMCODEKEY);
        session.setAttribute(RANDOMCODEKEY, randomString);
        g.dispose();
        try {
            // 将内存中的图片通过流动形式输出到客户端
            ImageIO.write(image, "JPEG", response.getOutputStream());
        } catch (Exception e) {
            logger.error("将内存中的图片通过流动形式输出到客户端失败>>>> ", e);
        }

    }

    /**
     * 绘制字符串
     */
    private String drowString(Graphics g, String randomString, int i) {
        g.setFont(getFont());
        g.setColor(new Color(random.nextInt(101), random.nextInt(111), random
                .nextInt(121)));
        String rand = String.valueOf(getRandomString(random.nextInt(randString
                .length())));
        randomString += rand;
        g.translate(random.nextInt(3), random.nextInt(3));
        g.drawString(rand, 13 * i, 16);
        return randomString;
    }

    /**
     * 绘制干扰线
     */
    private void drowLine(Graphics g) {
        int x = random.nextInt(width);
        int y = random.nextInt(height);
        int xl = random.nextInt(13);
        int yl = random.nextInt(15);
        g.drawLine(x, y, x + xl, y + yl);
    }

    /**
     * 获取随机的字符
     */
    public String getRandomString(int num) {
        return String.valueOf(randString.charAt(num));
    }
}
    /**
     * 生成验证码
     */
    @GetMapping(value = "/getVerify")
    public void getVerify(HttpServletRequest request, HttpServletResponse response) {
        try {
            response.setContentType("image/jpeg");//设置相应类型,告诉浏览器输出的内容为图片
            response.setHeader("Pragma", "No-cache");//设置响应头信息,告诉浏览器不要缓存此内容
            response.setHeader("Cache-Control", "no-cache");
            response.setDateHeader("Expire", 0);
            RandomValidateCodeUtil randomValidateCode = new RandomValidateCodeUtil();
            randomValidateCode.getRandcode(request, response);//输出验证码图片方法
        } catch (Exception e) {
            logger.error("获取验证码失败>>>> ", e);
        }
    }
<div class="col-xs-6 pull_left">
          <a href="javascript:void(0);" rel="external nofollow" title="点击更换验证码">
                 <img style="margin-top: 12px;" id="imgVerify" src="" alt="更换验证码" height="36" width="100%" onclick="getVerify(this);">
          </a>
</div>





    //获取验证码
    function getVerify(obj) {
        obj.src = "/getVerify?" + Math.random();   //加上随机数,切换图片,避免服务器缓存,相同路径,不再发送请求
        console.log(obj)
    }

关于请求头的设置

 图片来自菜鸟教程7.1.2 Android Http请求头与响应头的学习 | 菜鸟教程

表单验证

转自Validate表单验证_RocsLee筱站-CSDN博客_validate

validate属性,jquery的小插件

一、 validate的使用步骤

    引入jquery.min.js
    引入 jquery.validate.js
    页面加载后对表单进行验证 $("#表单id名").validate({})
    在validate中的rules中编写验证规则(格式如下)
        字段的name属性:“校验器”(tisps:一个输入框只有一个校验器的时候使用)
        字段的name属性:{校验器:值,校验器:值}(tips:输入框需要有多个校验器的时候使用)
    在validate中的messages中编写提示信息(tips格式与rules相对应)
    在validate中的submitHandler中编写验证通过执行的内容

二、实例

<!DOCTYPE html>
<html>
<head>
 <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<script type="text/javascript" src="scripts/common/jquery.min.js"></script>
<script type="text/javascript" src="scripts/common/jquery.validate.js"></script
<script type="text/javascript">
	 $("#zhuce").validate({
            rules:{
                regist_username:{
                    required:true
                   /* remote:{
                        type: "post",url: url,
                        data:{
                            userName:function () {
                                return $("regist_username").val();
                            }
                        }
                    }用ajax判断数据库中用户名是否存在*/
                },
                regist_password:{
                    required:true,
                    minlength:6
                },
                final_password:{
                    equalTo:"#regist_password"
                }
            },
            messages:{
                regist_username:{required:"用户名不能为空"},
                regist_password:{required:"密码不能为空",minlength:"密码最小的长度为6"},
                final_password:{equalTo:"两次密码不一致"}
            },
            submitHandler: function () {
            //验证通过后进行注册
                register();
            }
        })
  </script>
</head>
<body>
  <form id="zhuce">
            <dl>
                <dt>
                    <div class='header'>
                        <h3>注&nbsp;册</h3>
                    </div>
                </dt>
                <dt></dt>
                <dt>
                    <div class='letter'>
                        <label for="regist_username">用户名:&nbsp;</label>
                        <input type="text" name="regist_username" id="regist_username" tabindex='5'/>
                    </div>
                </dt>
                <dt>
                    <div class='letter'>
                        昵&nbsp;&nbsp;&nbsp;称:&nbsp;<input type="text" name="nickname" id="nickname" tabindex='6'/>
                    </div>
                </dt>
                <dt>
                    <div class='letter'>
                        <label for="regist_password"> 密&nbsp;&nbsp;&nbsp;码:&nbsp;</label>
                       <input type="password" name="regist_password" id="regist_password" tabindex='7'/>
                    </div>
                </dt>
                <dt>
                    <div class='password'>
                        <label for="final_password">&nbsp;&nbsp;&nbsp;确认密码:&nbsp;</label>
                        <input type="password" name="final_password" id="final_password" tabindex='8'/>
                    </div>
                </dt>
                <dt>
                    <div>
                        <input type="submit" name="" id="regist_button" value='&nbsp注&nbsp册&nbsp' tabindex='9'/>
                        <input type="button" name="" id="back" value='&nbsp返&nbsp回&nbsp' tabindex='10'/>
                    </div>
                </dt>
            </dl>
        </form>
</body>
</html>


实例二

    function validateRule() {
        var icon = "<i class='fa fa-times-circle'></i> ";
        $("#signupForm").validate({  //jquery插件验证表单内容
            rules: {
                username: {
                    required: true
                },
                password: {
                    required: true
                }
            },
            messages: {
                username: {
                    required: icon + "请输入您的用户名",
                },
                password: {
                    required: icon + "请输入您的密码",
                }
            }
        })
    }

详细使用jQuery validator 详解/应用_猿来是你-CSDN博客

获取model中数据

thymeleaf模板引擎为前端获取数据提供了较大的便利,在html标签可以通过th标签加${}表达式访问model中的数据。但是如果不想通过th标签而是简单的访问model对象数据,或者是在js中访问modle中的数据,则需要使用内联的方法。

比如我们可以使用[[$ {} ]]访问对象

<p>Hello, [[${session.user.name}]]!</p>

以上的代码可以取代一般的th标签写法

<p>Hello, <span th:text="${session.user.name}">Sebastian</span>!</p>

Expressions between [[...]] or [(...)] are considered inlined expressions in Thymeleaf。即使用此语法被称为“内联”。使用内联的语句的确会更加简洁一点。

若是想在javascript代码块内直接的使用model的对象值,则必须使用内联实现。

<script type="text/javascript" th:inline="javascript">
    /*<![CDATA[*/
    var max = /*[[${maxSumOfDateInYear}]]*/ 20;
    alert(max);
    /*]]>*/
</script>

其中第2、5行为基于XML的转义写法,第3行把内联访问的语句用注释引起来,且后面跟着一个空格20,是指若不存在此对象,则自动设置默认值为20。

  注意以上的javascript内联写法是基于你需要“直接地”使用model对象值的场景。否则还有其它写法,比如简单地声明一个hidden input:
 

<input type="hidden" id="maxSumOfDateInYear" th:value="${maxSumOfDateInYear}"/>
<script type="text/javascript" th:inline="none">
    var max = $("#maxSumOfDateInYear").val();
    var data = [["2012-05-07", 6], ["2012-04-16", 4]];
    alert(max);
    alert(data);
</script>

  以上第1行声明了一个hidden的maxSumOfDateInYear,然后第3行通过jQuery来间接访问。

  注意,若在thymeleaf代码里存在第4行的二维数组字面量的写法,则必须要把javascript代码块设置为inline为none的,否则thymeleaf引擎会把此数组的[[也当成了内联语句处理,从而导致后端报错An error happened during template parsing。要么,你就还是通过hidden间接访问的方式实现。

  或者,也可以通过ajax直接获取内容来实现。但这就属与thymeleaf模板引擎计算过程无关了。

thymeleaf的内联th:inline(在javascript访问model中的数据)_纱厨藤簟,玉人罗扇轻缣。-CSDN博客

登录验证

发送请求

    function login() {
        $.ajax({
            type: "POST",
            url: ctx + "login",
            //serialize() 方法通过序列化表单值,创建 URL 编码文本字符串。您可以选择一个或多个表单元素(比如 input 及/或 文本框),
            // 或者 form 元素本身。序列化的值可在生成 AJAX 请求时用于 URL 查询字符串中。
            data: $('#signupForm').serialize(),
            success: function (r) {
                if (r.code == 0) {
                    var index = layer.load(1, {
                        shade: [0.1, '#fff'] //0.1透明度的白色背景
                    });
                    // 父页面跳转 http://localhost/index
                    parent.location.href = '/index';
                } else {
                    //jquery插件 layer弹窗js
                    layer.msg(r.msg);
                }
            },
        });
    }

接收请求

    @PostMapping("/login")
    @ResponseBody
    R ajaxLogin(String username, String password,String verify,HttpServletRequest request) {

        try {
            //从session中获取验证码的值
            String random = (String) request.getSession().getAttribute(RandomValidateCodeUtil.RANDOMCODEKEY);
            if (StringUtils.isBlank(verify)) {  //isBlank 判空
                return R.error("请输入验证码");
            }
            if (random.equals(verify)) {
            } else {
                return R.error("请输入正确的验证码");
            }
        } catch (Exception e) {
            logger.error("验证码校验失败", e);
            return R.error("验证码校验失败");
        }
        // md5加盐算法后的密码
        password = MD5Utils.encrypt(username, password);
        UsernamePasswordToken token = new UsernamePasswordToken(username, password);
        Subject subject = SecurityUtils.getSubject();
        try {
            subject.login(token);
            return R.ok();
        } catch (AuthenticationException e) {
            return R.error("用户或密码错误");
        }
    }

R是一个标志类

import java.util.HashMap;
import java.util.Map;

public class R extends HashMap<String, Object> {
	private static final long serialVersionUID = 1L;

	public R() {
		put("code", 0);
		put("msg", "操作成功");
	}

	public static R error() {
		return error(1, "操作失败");
	}

	public static R error(String msg) {
		return error(500, msg);
	}

	public static R error(int code, String msg) {
		R r = new R();
		r.put("code", code);
		r.put("msg", msg);
		return r;
	}

	public static R ok(String msg) {
		R r = new R();
		r.put("msg", msg);
		return r;
	}

	public static R ok(Map<String, Object> map) {
		R r = new R();
		r.putAll(map);
		return r;
	}

	public static R ok() {
		return new R();
	}

	@Override
	public R put(String key, Object value) {
		super.put(key, value);
		return this;
	}
}

MD5加盐工具类


import org.apache.shiro.crypto.hash.SimpleHash;
import org.apache.shiro.util.ByteSource;

public class MD5Utils {
	private static final String SALT = "1qazxsw2";

	private static final String ALGORITH_NAME = "md5";

	private static final int HASH_ITERATIONS = 2;

	public static String encrypt(String pswd) {
		String newPassword = new SimpleHash(ALGORITH_NAME, pswd, ByteSource.Util.bytes(SALT), HASH_ITERATIONS).toHex();
		return newPassword;
	}

	public static String encrypt(String username, String pswd) {
		String newPassword = new SimpleHash(ALGORITH_NAME, pswd, ByteSource.Util.bytes(username + SALT),
				HASH_ITERATIONS).toHex();
		return newPassword;
	}
	public static void main(String[] args) {
		
//		System.out.println(MD5Utils.encrypt("admin", "111111"));
	}

}

对MD5加盐不太了解的可以看这篇文章使用Shiro的SimpleHash加密密码工具类_mr_foxsand的专栏-CSDN博客

关于ajax的页面跳转

使用AJAX实现页面跳转 - 南哥的天下 - 博客园

页面跳转的几种形式

  1. window.parent.location 用于更改父窗口的位置。

  2. window.top.location

    • 它是对象'window'的属性。
    • 它返回窗口层次结构中最顶层窗口的位置。
    • 如果窗口没有父窗口,则top是对自身的引用(窗口=== window.top)

window.top.location.href 和 window.location.href 的区别 - 戒不掉n_思念 - 博客园

日志记录

使用aop横切日志

package com.bootdo.common.aspect;

import com.bootdo.common.utils.HttpContextUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import sun.net.util.IPAddressUtil;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.Arrays;

@Aspect
@Component
public class WebLogAspect {

    private static final Logger logger = LoggerFactory.getLogger(WebLogAspect.class);

    @Pointcut("execution( * com.bootdo..controller.*.*(..))")//两个..代表所有子目录,最后括号里的两个..代表所有参数
    public void logPointCut() {
    }


    @Before("logPointCut()")
    public void doBefore(JoinPoint joinPoint) throws Throwable {
        // 接收到请求,记录请求内容
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();

        // 记录下请求内容
        logger.info("请求地址 : " + request.getRequestURL().toString());
        logger.info("HTTP METHOD : " + request.getMethod());
        // 获取真实的ip地址
        //logger.info("IP : " + IPAddressUtil.getClientIpAddress(request));
        logger.info("CLASS_METHOD : " + joinPoint.getSignature().getDeclaringTypeName() + "."
                + joinPoint.getSignature().getName());
        logger.info("参数 : " + Arrays.toString(joinPoint.getArgs()));
//        loggger.info("参数 : " + joinPoint.getArgs());

    }

    @AfterReturning(returning = "ret", pointcut = "logPointCut()")// returning的值和doAfterReturning的参数名一致
    public void doAfterReturning(Object ret) throws Throwable {
        // 处理完请求,返回内容(返回值太复杂时,打印的是物理存储空间的地址)
        logger.debug("返回值 : " + ret);
    }

    @Around("logPointCut()")
    public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
        long startTime = System.currentTimeMillis();
        Object ob = pjp.proceed();// ob 为方法的返回值
        logger.info("耗时 : " + (System.currentTimeMillis() - startTime));
        return ob;
    }
}

Spring AOP 中@Pointcut的用法 - 山高我为峰 - 博客园

授权方式: 开源软件 界面语言: 简体中文 文件大小: 12.3 MB 更新时间: 2020-08-12 资源类型: 国产软件 推荐等级: ★★★☆☆ 平台环境: JAVA 作者主页: 点击查看 演示地址: 点击查看 详细介绍 – [ BootDo后台管理系统 v1.0 ] BootDo 是高效率,低封装,面向学习型,面向微服的开源JavaEE开发框架BootDo是在SpringBoot基础上搭建的一个Java基础开发平台,MyBatis为数据访问层,ApacheShiro为权限授权层,Ehcahe对常用数据进行缓存。 BootDo主要定位于后台管理系统学习交流,已内置后台管理系统的基础功能和高效的代码生成工具,包括:系统权限组件、数据权限组件、数据字典组件、核心工具组件、视图操作组件、工作流组件、代码生成等。前端界面风格采用了结构简单、性能优良、页面美观大气的TwitterBootstrap页面展示框架。采用分层设计、双重验证、提交数据安全编码、密码加密、访问验证、数据权限验证。使用Maven做项目管理,提高项目的易开发性、扩展性。 BootDo目前包括以下四大模块,系统管理(SYS)模块、内容管理(CMS)模块、在线办公(OA)模块、代码生成(GEN)模块。系统管理模块,包括企业组织架构(用户管理、机构管理、区域管理)、菜单管理、角色权限管理、字典管理等功能;内容管理模块,包括内容管理(文章、链接),栏目管理、站点管理、公共留言、文件管理、前端网站展示等功能;在线办公模块,提供简单的请假流程实例;代码生成模块,完成重复的工作。 BootDo提供了常用工具进行封装,包括日志工具、缓存工具、服务器端验证、数据字典、当前组织机构数据(用户、机构、区域)以及其它常用小工具等。另外还提供一个强大的在线代码生成工具。 BootDo内置功能 用户管理:用户是系统操作者,该功能主要完成系统用户配置。 机构管理:配置系统组织机构(公司、部门、小组),树结构展现,可随意调整上下级。 区域管理:系统城市区域模型,如:国家、省市、地市、区县的维护。 菜单管理:配置系统菜单,操作权限,按钮权限标识等。 角色管理:角色菜单权限分配、设置角色按机构进行数据范围权限划分。 字典管理:对系统中经常使用的一些较为固定的数据进行维护,如:是否、男女、类别、级别等。 操作日志:系统正常操作日志记录和查询;系统异常信息日志记录和查询。 连接池监视:监视当期系统数据库连接池状态,可进行分析SQL找出系统性能瓶颈。 工作流引擎:实现业务工单流转、在线流程设计器。 BootDo截图 相关阅读 同类推荐: 站长常用源码
BootDo是高效率,低封装,面向学习型,面向微服的开源JavaEE开发框架BootDo是在SpringBoot基础上搭建的一个Java基础开发平台,MyBatis为数据访问层,ApacheShiro为权限授权层,Ehcahe对常用数据进行缓存。 BootDo主要定位于后台管理系统学习交流,已内置后台管理系统的基础功能和高效的代码生成工具,包括:系统权限组件、数据权限组件、数据字典组件、核心工具组件、视图操作组件、工作流组件、代码生成等。前端界面风格采用了结构简单、性能优良、页面美观大气的TwitterBootstrap页面展示框架。采用分层设计、双重验证、提交数据安全编码、密码加密、访问验证、数据权限验证。使用Maven做项目管理,提高项目的易开发性、扩展性。 BootDo目前包括以下四大模块,系统管理(SYS)模块、内容管理(CMS)模块、在线办公(OA)模块、代码生成(GEN)模块。系统管理模块,包括企业组织架构(用户管理、机构管理、区域管理)、菜单管理、角色权限管理、字典管理等功能;内容管理模块,包括内容管理(文章、链接),栏目管理、站点管理、公共留言、文件管理、前端网站展示等功能;在线办公模块,提供简单的请假流程实例;代码生成模块,完成重复的工作。 BootDo提供了常用工具进行封装,包括日志工具、缓存工具、服务器端验证、数据字典、当前组织机构数据(用户、机构、区域)以及其它常用小工具等。另外还提供一个强大的在线代码生成工具。 内置功能: 用户管理:用户是系统操作者,该功能主要完成系统用户配置。 机构管理:配置系统组织机构(公司、部门、小组),树结构展现,可随意调整上下级。 区域管理:系统城市区域模型,如:国家、省市、地市、区县的维护。 菜单管理:配置系统菜单,操作权限,按钮权限标识等。 角色管理:角色菜单权限分配、设置角色按机构进行数据范围权限划分。 字典管理:对系统中经常使用的一些较为固定的数据进行维护,如:是否、男女、类别、级别等。 操作日志:系统正常操作日志记录和查询;系统异常信息日志记录和查询。 连接池监视:监视当期系统数据库连接池状态,可进行分析SQL找出系统性能瓶颈。 工作流引擎:实现业务工单流转、在线流程设计器。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值