1、pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0modelVersion>
<parent>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-parentartifactId>
<version>2.1.14.RELEASEversion>
<relativePath/>
parent>
<groupId>cn.lemongroupId>
<artifactId>demoartifactId>
<version>0.0.1-SNAPSHOTversion>
<name>demoname>
<description>Demo project for Spring Bootdescription>
<properties>
<project.build.sourceEncoding>UTF-8project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8project.reporting.outputEncoding>
<java.version>1.8java.version>
properties>
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-loggingartifactId>
exclusion>
exclusions>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-log4j2artifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-thymeleafartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-jdbcartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-testartifactId>
<scope>testscope>
dependency>
<dependency>
<groupId>org.mybatis.spring.bootgroupId>
<artifactId>mybatis-spring-boot-starterartifactId>
<version>2.1.1version>
dependency>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<version>5.1.46version>
dependency>
<dependency>
<groupId>net.sf.json-libgroupId>
<artifactId>json-libartifactId>
<version>2.4version>
<classifier>jdk15classifier>
dependency>
<dependency>
<groupId>junitgroupId>
<artifactId>junitartifactId>
<version>4.12version>
<scope>testscope>
dependency>
<dependency>
<groupId>commons-langgroupId>
<artifactId>commons-langartifactId>
<version>2.6version>
dependency>
<dependency>
<groupId>com.alibabagroupId>
<artifactId>druid-spring-boot-starterartifactId>
<version>1.1.10version>
dependency>
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
dependency>
dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-maven-pluginartifactId>
plugin>
plugins>
build>
project>
2、application.properties
或者(application.yml
)
## 端口
server.port=8080
##
server.servlet.context-path=/
##数据源配置
##连接池类型
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
##数据库驱动
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
##数据库
spring.datasource.url=jdbc:mysql://localhost:3306/db_base_ssm
##用户名
spring.datasource.username=root
##密码
spring.datasource.password=root
##连接池配置-初始化时建立物理连接的个数。初始化发生在显示调用init方法,或者第一次getConnection时
spring.datasource.druid.initial-size=5
##连接池配置-最小连接数
spring.datasource.druid.min.idle=5
##连接池配置-最大连接数
spring.datasource.druid.max-active=20
##连接池配置-等待超时的时间,单位毫秒。配置了maxWait之后,缺省启用公平锁,并发效率会有所下降,如果需要可以通过配置useUnfairLock属性为true使用非公平锁。
spring.datasource.druid.max-wait=60000
##连接池配置-是否缓存preparedStatement,也就是PSCache。PSCache对支持游标的数据库性能提升巨大,比如说oracle。在mysql下建议关闭。
spring.datasource.druid.pool-prepared-statements=false
##连接池配置-要启用PSCache,必须配置大于0,当大于0时,poolPreparedStatements自动触发修改为true。在Druid中,不会存在Oracle下PSCache占用内存过多的问题,可以把这个数值配置大一些,比如说100
spring.datasource.druid.max-open-prepared-statements=-1
##连接池配置-申请连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。
spring.datasource.druid.test-on-borrow=false
##连接池配置-归还连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能
spring.datasource.druid.test-on-return=false
##连接池配置-建议配置为true,不影响性能,并且保证安全性。申请连接的时候检测,如果空闲时间大于timeBetweenEvictionRunsMillis,执行validationQuery检测连接是否有效。
spring.datasource.druid.test-while-idle=true
##连接池配置-间隔多久才进行一次检测,检测需要关闭的空闲连接,单位毫秒
spring.datasource.druid.time-between-eviction-runs-millis=60000
##连接池配置-配置一个连接在池中最小生存时间,单位毫秒
spring.datasource.druid.min-evictable-idle-time-millis=300000
##MyBatis配置
mybatis.mapper-locations=classpath*:mybatis/*.xml
mybatis.type-aliases-package=cn.lemon.demo.domain
#配置访问静态文件
spring.mvc.static-path-pattern=/static/**
#thymelea模板配置
#默认页面映射路径
spring.thymeleaf.prefix=classpath:/templates/
spring.thymeleaf.suffix=.html
spring.thymeleaf.mode=HTML5
spring.thymeleaf.encoding=UTF-8
spring.thymeleaf.servlet.content-type=text/html
#热部署文件,页面不产生缓存,及时更新。关闭模板缓存
spring.thymeleaf.cache=false
spring.resources.chain.strategy.content.enabled=true
spring.resources.chain.strategy.content.paths=/**
##指定log4j2配置文件
logging.config=classpath:log4j2-spring.xml
logging.level.cn.lemon.demo=debug
3、log4j2-spring.xml
<Configuration status="DEBUG">
<Appenders>
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="%d{YYYY-MM-dd HH:mm:ss} [%t] %-5p %c{1}:%L - %msg%n"/>
Console>
<RollingFile name="RollingFile" filename="log/test.log" filepattern="${logPath}/%d{YYYYMMddHHmmss}-fargo.log">
<PatternLayout pattern="%d{YYYY-MM-dd HH:mm:ss} [%t] %-5p %c{1}:%L - %msg%n"/>
<Policies>
<SizeBasedTriggeringPolicy size="10 MB"/>
Policies>
<DefaultRolloverStrategy max="20"/>
RollingFile>
Appenders>
<Loggers>
<Root level="info">
<AppenderRef ref="Console"/>
<AppenderRef ref="RollingFile"/>
Root>
Loggers>
Configuration>
1、实体类 User.java
package cn.lemon.demo.domain.admin;
import lombok.Getter;
import lombok.Setter;
import org.springframework.stereotype.Component;
@Component
@Getter
@Setter
public class User {
private Integer id;
private String username;
private String password;
private String photo;
private int sex;//0:未知;1:男;2:女
private int age;
private String address;
}
2、数据访问层 IUserDao.java
和 映射文件 IUserDao.xml
package cn.lemon.demo.dao.admin;
import cn.lemon.demo.domain.admin.User;
import org.springframework.stereotype.Repository;
@Repository
public interface IUserDao {
User findByUsername(String username);
}
<mapper namespace="cn.lemon.demo.dao.admin.IUserDao">
<select id="findByUsername" resultType="User" parameterType="String">
select * from user where username = #{username}
select>
mapper>
3、业务逻辑层 IUserService.java
、UserServiceImpl.java
package cn.lemon.demo.service.admin;
import cn.lemon.demo.domain.admin.User;
import org.springframework.stereotype.Service;
@Service
public interface IUserService {
User findByUsername(String username);
}
package cn.lemon.demo.service.admin.impl;
import cn.lemon.demo.dao.admin.IUserDao;
import cn.lemon.demo.domain.admin.User;
import cn.lemon.demo.service.admin.IUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class UserServiceImpl implements IUserService {
@Autowired
private IUserDao iUserDao;
@Override
public User findByUsername(String username) {
return iUserDao.findByUsername(username);
}
}
4、控制层 SystemController.java
package cn.lemon.demo.controller.admin;
import cn.lemon.demo.domain.admin.User;
import cn.lemon.demo.service.admin.impl.UserServiceImpl;
import cn.lemon.demo.utils.CpachaUtil;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.ModelAndView;
import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
@Controller
@RequestMapping("/system")
public class SystemController {
@Autowired
private UserServiceImpl userService;
//404 页面
@GetMapping(value = "/404")
public String error_404() {
return "/errors/404";
}
//500页面
@GetMapping(value = "/500")
public String error_500() {
return "/errors/500";
}
//登录页面
@RequestMapping(value = "/login", method = RequestMethod.GET)
public ModelAndView login(ModelAndView model) {
model.setViewName("/system/login");
return model;
}
//登录后的主页
@RequestMapping(value = "/index", method = RequestMethod.GET)
public ModelAndView index(ModelAndView model) {
model.setViewName("/system/index");
return model;
}
//登录表单处理
@RequestMapping(value = "/login", method = RequestMethod.POST)
@ResponseBody
public Map<String, String> loginAct(User user, String cpacha, HttpServletRequest request) {
Map<String, String> ret = new HashMap<String, String>();
if (user == null) {
ret.put("type", "error");
ret.put("msg", "请填写用户信息!");
return ret;
}
if (StringUtils.isEmpty(cpacha)) {
ret.put("type", "error");
ret.put("msg", "请填写验证码!");
return ret;
}
if (StringUtils.isEmpty(user.getUsername())) {
ret.put("type", "error");
ret.put("msg", "请填写用户名!");
return ret;
}
if (StringUtils.isEmpty(user.getPassword())) {
ret.put("type", "error");
ret.put("msg", "请填写密码!");
return ret;
}
Object loginCpacha = request.getSession().getAttribute("loginCpacha");
if (loginCpacha == null) {
ret.put("type", "error");
ret.put("msg", "登录超时,请重新登录!");
return ret;
}
if (!cpacha.toUpperCase().equals(loginCpacha.toString().toUpperCase())) {
ret.put("type", "error");
ret.put("msg", "验证码错误!");
return ret;
}
User findByUsername = userService.findByUsername(user.getUsername());
if (findByUsername == null) {
ret.put("type", "error");
ret.put("msg", "用户名不存在!");
return ret;
}
if (!user.getPassword().equals(findByUsername.getPassword())) {
ret.put("type", "error");
ret.put("msg", "密码错误!");
return ret;
}
// 把登录的用户写进 Session
request.getSession().setAttribute("admin", findByUsername);
ret.put("type", "success");
ret.put("msg", "登录成功!");
return ret;
}
//获取验证码
@RequestMapping(value = "/get_cpacha", method = RequestMethod.GET)
public void generateCpacha(
@RequestParam(name = "vl", required = false, defaultValue = "4") Integer vcodeLen,
@RequestParam(name = "w", required = false, defaultValue = "110") Integer width,
@RequestParam(name = "h", required = false, defaultValue = "30") Integer height,
@RequestParam(name = "type", required = true, defaultValue = "loginCpacha") String cpacheType,
HttpServletRequest request, HttpServletResponse response) {
CpachaUtil cpachaUtil = new CpachaUtil(vcodeLen, width, height);
String generatorVCode = cpachaUtil.generatorVCode();// 生成随机字符串
request.getSession().setAttribute(cpacheType, generatorVCode);// 写入Session
BufferedImage generatorRotateVCodeImage = cpachaUtil.generatorRotateVCodeImage(generatorVCode, true);// 创建图片
try {
ImageIO.write(generatorRotateVCodeImage, "gif", response.getOutputStream());// 输出流
} catch (IOException e) {
e.printStackTrace();
}
}
}
5、错误页面配置类 ErrorPageController.java
package cn.lemon.demo.config;
import org.springframework.boot.web.server.ErrorPage;
import org.springframework.boot.web.server.ErrorPageRegistrar;
import org.springframework.boot.web.server.ErrorPageRegistry;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
@Component
public class ErrorPageConfig implements ErrorPageRegistrar {
@Override
public void registerErrorPages(ErrorPageRegistry errorPageRegistry) {
//1、按错误的类型显示错误的网页
//错误类型为404,找不到网页的,默认显示404.html网页
ErrorPage e404 = new ErrorPage(HttpStatus.NOT_FOUND, "/system/404");
//错误类型为500,表示服务器响应错误,默认显示500.html网页
ErrorPage e500 = new ErrorPage(HttpStatus.INTERNAL_SERVER_ERROR, "/system/500");
errorPageRegistry.addErrorPages(e404, e500);
}
}
1、登录拦截器 LoginInterceptor.java
package cn.lemon.demo.interceptor.admin;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.HashMap;
import java.util.Map;
import net.sf.json.JSONObject;
@Component
public class LoginInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String requestURI = request.getRequestURI();
Object admin = request.getSession().getAttribute("admin");
if (admin == null) {
System.out.println("连接" + requestURI + "被拦截");
// 判断是否是 Ajax请求
String header = request.getHeader("X-Requested-With");
if ("XMLHttpRequest".equals(header)) {
// 表示是Ajax 请求
Map<String, String> ret = new HashMap<String, String>();
ret.put("type", "error");
ret.put("msg", "登录会话超时或未登录,请重新登录!");
response.getWriter().write(JSONObject.fromObject(ret).toString());
return false;
}
// 表示普通连接跳转,直接跳转到登录页面
// 如果 Session 里没有admin这个用户,也就是登录失效或者未登录,直接重定向到登录页面
response.sendRedirect(request.getServletContext().getContextPath() + "/system/login");
return false;
}
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
}
}
2、注册拦截器 WebConfigurer.java
package cn.lemon.demo.interceptor.admin;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class WebConfigurer implements WebMvcConfigurer {
@Autowired
private LoginInterceptor loginInterceptor;
// 这个方法是用来配置静态资源的,比如html,js,css,等等
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
}
// 这个方法用来注册拦截器,我们自己写好的拦截器需要通过这里添加注册才能生效
@Override
public void addInterceptors(InterceptorRegistry registry) {
//添加拦截地址,登录地址与静态文件不拦截
String[] excludes = new String[]{"/system/login","/static/**","/errors/**","/system/get_cpacha"};
// addPathPatterns("/**") 表示拦截所有的请求,
// excludePathPatterns("/login", "/register") 表示除了登陆与注册之外,因为登陆注册不需要登陆也可以访问
registry.addInterceptor(loginInterceptor).addPathPatterns("/**").excludePathPatterns(excludes);
//super.addInterceptors(registry); //较新Spring Boot的版本中这里可以直接去掉,否则会报错
}
}
1、 CpachaUtil.java
package cn.lemon.demo.utils;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.util.Random;
/**
* 验证码生成器
*
* @author llq
*/
public class CpachaUtil {
/**
* 验证码来源
*/
final private char[] code = {
'2', '3', '4', '5', '6', '7', '8', '9',
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j',
'k', 'm', 'n', 'p', 'q', 'r', 's', 't', 'u', 'v',
'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D', 'E', 'F',
'G', 'H', 'J', 'K', 'L', 'M', 'N', 'P', 'Q', 'R',
'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'
};
/**
* 字体
*/
final private String[] fontNames = new String[]{
"黑体", "宋体", "Courier", "Arial",
"Verdana", "Times", "Tahoma", "Georgia"};
/**
* 字体样式
*/
final private int[] fontStyles = new int[]{
Font.BOLD, Font.ITALIC|Font.BOLD
};
/**
* 验证码长度
* 默认4个字符
*/
private int vcodeLen = 4;
/**
* 验证码图片字体大小
* 默认17
*/
private int fontsize = 21;
/**
* 验证码图片宽度
*/
private int width = (fontsize+1)*vcodeLen+10;
/**
* 验证码图片高度
*/
private int height = fontsize+12;
/**
* 干扰线条数
* 默认3条
*/
private int disturbline = 3;
public CpachaUtil(){
}
/**
* 指定验证码长度
* @param vcodeLen 验证码长度
*/
public CpachaUtil(int vcodeLen) {
this.vcodeLen = vcodeLen;
this.width = (fontsize+1)*vcodeLen+10;
}
/**
* 指定验证码长度、图片宽度、高度
* @param vcodeLen
* @param width
* @param height
*/
public CpachaUtil(int vcodeLen,int width,int height) {
this.vcodeLen = vcodeLen;
this.width = width;
this.height = height;
}
/**
* 生成验证码图片
* @param vcode 要画的验证码
* @param drawline 是否画干扰线
* @return
*/
public BufferedImage generatorVCodeImage(String vcode, boolean drawline){
//创建验证码图片
BufferedImage vcodeImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
Graphics g = vcodeImage.getGraphics();
//填充背景色
g.setColor(new Color(246, 240, 250));
g.fillRect(0, 0, width, height);
if(drawline){
drawDisturbLine(g);
}
//用于生成伪随机数
Random ran = new Random();
//在图片上画验证码
for(int i = 0;i < vcode.length();i++){
//设置字体
g.setFont(new Font(fontNames[ran.nextInt(fontNames.length)], fontStyles[ran.nextInt(fontStyles.length)], fontsize));
//随机生成颜色
g.setColor(getRandomColor());
//画验证码
g.drawString(vcode.charAt(i)+"", i*fontsize+10, fontsize+5);
}
//释放此图形的上下文以及它使用的所有系统资源
g.dispose();
return vcodeImage;
}
/**
* 获得旋转字体的验证码图片
* @param vcode
* @param drawline 是否画干扰线
* @return
*/
public BufferedImage generatorRotateVCodeImage(String vcode, boolean drawline){
//创建验证码图片
BufferedImage rotateVcodeImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
Graphics2D g2d = rotateVcodeImage.createGraphics();
//填充背景色
g2d.setColor(new Color(246, 240, 250));
g2d.fillRect(0, 0, width, height);
if(drawline){
drawDisturbLine(g2d);
}
//在图片上画验证码
for(int i = 0;i < vcode.length();i++){
BufferedImage rotateImage = getRotateImage(vcode.charAt(i));
g2d.drawImage(rotateImage, null, (int) (this.height * 0.7) * i, 0);
}
g2d.dispose();
return rotateVcodeImage;
}
/**
* 生成验证码
* @return 验证码
*/
public String generatorVCode(){
int len = code.length;
Random ran = new Random();
StringBuffer sb = new StringBuffer();
for(int i = 0;i < vcodeLen;i++){
int index = ran.nextInt(len);
sb.append(code[index]);
}
return sb.toString();
}
/**
* 为验证码图片画一些干扰线
* @param g
*/
private void drawDisturbLine(Graphics g){
Random ran = new Random();
for(int i = 0;i < disturbline;i++){
int x1 = ran.nextInt(width);
int y1 = ran.nextInt(height);
int x2 = ran.nextInt(width);
int y2 = ran.nextInt(height);
g.setColor(getRandomColor());
//画干扰线
g.drawLine(x1, y1, x2, y2);
}
}
/**
* 获取一张旋转的图片
* @param c 要画的字符
* @return
*/
private BufferedImage getRotateImage(char c){
BufferedImage rotateImage = new BufferedImage(height, height, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = rotateImage.createGraphics();
//设置透明度为0
g2d.setColor(new Color(255, 255, 255, 0));
g2d.fillRect(0, 0, height, height);
Random ran = new Random();
g2d.setFont(new Font(fontNames[ran.nextInt(fontNames.length)], fontStyles[ran.nextInt(fontStyles.length)], fontsize));
g2d.setColor(getRandomColor());
double theta = getTheta();
//旋转图片
g2d.rotate(theta, height/2, height/2);
g2d.drawString(Character.toString(c), (height-fontsize)/2, fontsize+5);
g2d.dispose();
return rotateImage;
}
/**
* @return 返回一个随机颜色
*/
private Color getRandomColor(){
Random ran = new Random();
return new Color(ran.nextInt(220), ran.nextInt(220), ran.nextInt(220));
}
/**
* @return 角度
*/
private double getTheta(){
return ((int) (Math.random()*1000) % 2 == 0 ? -1 : 1)*Math.random();
}
/**
* @return 验证码字符个数
*/
public int getVcodeLen() {
return vcodeLen;
}
/**
* 设置验证码字符个数
* @param vcodeLen
*/
public void setVcodeLen(int vcodeLen) {
this.width = (fontsize+3)*vcodeLen+10;
this.vcodeLen = vcodeLen;
}
/**
* @return 字体大小
*/
public int getFontsize() {
return fontsize;
}
/**
* 设置字体大小
* @param fontsize
*/
public void setFontsize(int fontsize) {
this.width = (fontsize+3)*vcodeLen+10;
this.height = fontsize+15;
this.fontsize = fontsize;
}
/**
* @return 图片宽度
*/
public int getWidth() {
return width;
}
/**
* 设置图片宽度
* @param width
*/
public void setWidth(int width) {
this.width = width;
}
/**
* @return 图片高度
*/
public int getHeight() {
return height;
}
/**
* 设置图片高度
* @param height
*/
public void setHeight(int height) {
this.height = height;
}
/**
* @return 干扰线条数
*/
public int getDisturbline() {
return disturbline;
}
/**
* 设置干扰线条数
* @param disturbline
*/
public void setDisturbline(int disturbline) {
this.disturbline = disturbline;
}
}
1、登录 login.html
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<title>登录title>
<meta name="description" content="particles.js is a lightweight JavaScript library for creating particles.">
<meta name="author" content="Vincent Garreau">
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no">
<link rel="stylesheet" media="screen" th:href="@{/static/login/css/style.css}">
<link rel="stylesheet" type="text/css" th:href="@{/static/login/css/reset.css}">
head>
<body>
<div id="particles-js">
<div class="login" style="display: block;">
<div class="login-top">登录div>
<div class="login-center clearfix">
<div class="login-center-img">
<img src="/static/login/images/name.png">
div>
<div class="login-center-input">
<input type="text" name="username" id="username" value=""
placeholder="请输入您的用户名" onfocus="this.placeholder=''"
onblur="this.placeholder='请输入您的用户名'">
<div class="login-center-input-text">用户名div>
div>
div>
<div class="login-center clearfix">
<div class="login-center-img">
<img src="/static/login/images/password.png">
div>
<div class="login-center-input">
<input type="password" name="password" id="password" value=""
placeholder="请输入您的密码" onfocus="this.placeholder=''"
onblur="this.placeholder='请输入您的密码'">
<div class="login-center-input-text">密码div>
div>
div>
<div class="login-center clearfix">
<div class="login-center-img">
<img src="/static/login/images/cpacha.png">
div>
<div class="login-center-input">
<input type="text" style="width: 50%;" name="cpacha" id="cpacha"
value="" placeholder="请输入验证码"
onfocus="this.placeholder=''"
onblur="this.placeholder='请输入验证码'">
<div class="login-center-input-text">验证码div>
<img id="cpacha-img" style="cursor: pointer;" title="点击切换验证码"
src="get_cpacha?vl=4&w=100&h=30&type=loginCpacha" width="110px"
height="30px" onclick="changeCpacha()">
div>
div>
<div class="login-button">登录div>
div>
<div class="sk-rotating-plane">div>
<canvas class="particles-js-canvas-el" width="1147" height="952"
style="width: 100%; height: 100%;">canvas>
div>
<script th:src="@{/static/login/js/particles.min.js}">script>
<script th:src="@{/static/login/js/jquery-1.8.0.min.js}">script>
<script th:src="@{/static/login/js/app.js}">script>
<script type="text/javascript">
function hasClass(elem, cls) {
cls = cls || '';
if (cls.replace(/\s/g, '').length == 0) return false; //当cls没有参数时,返回false
return new RegExp(' ' + cls + ' ').test(' ' + elem.className + ' ');
}
function addClass(ele, cls) {
if (!hasClass(ele, cls)) {
ele.className = ele.className == '' ? cls : ele.className + ' ' + cls;
}
}
function removeClass(ele, cls) {
if (hasClass(ele, cls)) {
var newClass = ' ' + ele.className.replace(/[\t\r\n]/g, '') + ' ';
while (newClass.indexOf(' ' + cls + ' ') >= 0) {
newClass = newClass.replace(' ' + cls + ' ', ' ');
}
ele.className = newClass.replace(/^\s+|\s+$/g, '');
}
}
function changeCpacha() {
$("#cpacha-img").attr("src", 'get_cpacha?vl=4&w=100&h=30&type=loginCpacha&t=' + new Date().getTime());
}
document.querySelector(".login-button").onclick = function () {
var username = $("#username").val();
var password = $("#password").val();
var cpacha = $("#cpacha").val();
if (username == '' || username == 'undefined') {
alert("请填写用户名!");
return;
}
if (password == '' || password == 'undefined') {
alert("请填写密码!");
return;
}
if (cpacha == '' || cpacha == 'undefined') {
alert("请填写验证码!");
return;
}
addClass(document.querySelector(".login"), "active")
addClass(document.querySelector(".sk-rotating-plane"), "active")
document.querySelector(".login").style.display = "none"
/* setTimeout(function(){
addClass(document.querySelector(".sk-rotating-plane"), "active")
document.querySelector(".login").style.display = "none"
},800) */
$.ajax({
url: "login",
data: {username: username, password: password, cpacha: cpacha},
type: 'post',
dataType: 'json',
success: function (data) {
if (data.type == 'success') {
window.location = 'index';
} else {
removeClass(document.querySelector(".login"), "active")
removeClass(document.querySelector(".sk-rotating-plane"), "active")
document.querySelector(".login").style.display = "block"
alert(data.msg);
changeCpacha();
}
}
});
}
script>
body>
html>
2、 404.html
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>页面找不到title>
<link href="/static/h-ui/css/H-ui.min.css" rel="stylesheet" type="text/css" />
<link href="/static/h-ui/lib/Hui-iconfont/1.0.1/iconfont.css" rel="stylesheet" type="text/css" />
head>
<body>
<div class="page-404 text-c">
<p class="error-title"><i class="Hui-iconfont">i>404p>
<p class="error-description">不好意思,您访问的页面不存在~p>
div>
body>
html>
3、 500.html
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>服务端错误title>
<link href="/static/h-ui/css/H-ui.min.css" rel="stylesheet" type="text/css" />
<link href="/static/h-ui/lib/Hui-iconfont/1.0.1/iconfont.css" rel="stylesheet" type="text/css" />
head>
<body>
<div class="page-404 text-c">
<p class="error-title"><i class="Hui-iconfont">i>500p>
<p class="error-description">不好意思,服务端错误啦~p>
div>
body>
html>
点击下载