此项目主要用到了springboot、mybatis、log4j2日志等。
项目结构:
首先建立pom.xml,其中主要依赖都是自动生成的,只有配置log4j2时需要注意:log4j2导入
log4j2可能的错误
添加日志功能:springboot1.3以上使用log4j2。首先在pom.xml中exclude掉springboot默认的log,然后导入log4j2依赖,配置xml,并再yaml中配置其路径
1、实体类
package com.example.spbdemo01.Pojo;
public class User {
private String name;
private String password;
public User(String name, String password) {
this.name = name;
this.password = password;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public User() {
}
}
2、数据层接口:Daomapper:
package com.example.spbdemo01.Dao;
import com.example.spbdemo01.Pojo.User;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.springframework.stereotype.Repository;
@Repository
@Mapper
public interface Daomapper {
User getInfo(@Param("name") String name, @Param("password") String password);
}
3、mapper映射文件:
<?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.example.spbdemo01.Dao.Daomapper">
<select id="getInfo" resultType="user">
select * from accountlist where name=#{name} and password=#{password}
</select>
</mapper>
4、service层接口
package com.example.spbdemo01.Service;
import com.example.spbdemo01.Pojo.User;
public interface Servicemapper{
public User getUser(String name,String password);
}
5、service层实现类:
package com.example.spbdemo01.Service;
import com.example.spbdemo01.Dao.Daomapper;
import com.example.spbdemo01.Pojo.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
@Service
public class serviceImp implements Servicemapper{
@Autowired
private Daomapper daomapper;
@Override
public User getUser(String name, String password) {
User user=daomapper.getInfo(name,password);
return user;
}
}
6、controller层:
日志门面
Hellocontroller:
package com.example.spbdemo01.Controller;
import com.example.spbdemo01.Pojo.User;
import com.example.spbdemo01.Service.Servicemapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
@Controller
@Slf4j //日志门面,使用此注解省去了log4j2的一些配置
public class Hellocontroller {
@Autowired
Servicemapper servicemapper;
@RequestMapping("/hello")
public String hello(){
return "index";
}
@GetMapping("/testlog")
@ResponseBody
public String testlog(){
log.info("info日志");
log.warn("warn日志");
return "测试log4j2";
}
}
Checkcontroller:(Get、Post方法要与前端保持一致)
表单提交用Post多,超链接href用Get
package com.example.spbdemo01.Controller;
import com.example.spbdemo01.Pojo.User;
import com.example.spbdemo01.Service.Servicemapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import javax.servlet.http.HttpSession;
@Controller
@Slf4j
public class Checkcontroller {
@Autowired
Servicemapper servicemapper;
//之前用的check,可能check为关键字
@RequestMapping("/login")
public String show(){
return "check";
}
@PostMapping("/login2")
//这里不能写Get(因为要与前端页面中的方法保持一致),可以使用PostMapping或者RequestMapping(支持Get和Post)
public String checkin(@RequestParam("name") String name, @RequestParam("password") String password,
HttpSession session){
User user= servicemapper.getUser(name,password);
if(user!=null){
session.setAttribute("loginuser","username");
return "redirect:/bingo";
}else{
return "redirect:/login";
//账号或密码错误,登录失败,重定向到登录页面
}
}
/*
//也可以用get,url传参(记得修改前端的传参方式)
@GetMapping("/login2/{name}/{password}")
//这里不能用Get,可以使用PostMapping或者RequestMapping(支持Get和Post)
public String checkin(@PathVariable("name") String name, @PathVariable("password") String password,
HttpSession session){
User user= servicemapper.getUser(name,password);
if(user!=null){
session.setAttribute("loginuser","username");
return "redirect:/bingo";
}else{
return "redirect:/login";
//账号或密码错误,登录失败,重定向到登录页面
}
}
*/
@GetMapping("/logout")
//之前使用的是@PostMapping("/logout"),报错
public String logout(HttpSession session){
session.removeAttribute("loginuser");
return "redirect:/login";
}
}
7、登录拦截器:
“”就表示了所有的文件,但是“”并不包括子目录下的文件;
“**”匹配包含任意级子目录中所有的文件
package com.example.spbdemo01.config;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class Loginintercepter implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
if(request.getSession().getAttribute("loginuser")!=null){
return true;
}else{
request.getRequestDispatcher("/login").forward(request,response);
return false;
}
}
}
8、配置mvc扩展:
addViewController为html文件配置路由,否则登录后的url路径和没登陆一样了,不好区分
package com.example.spbdemo01.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class mvconfig implements WebMvcConfigurer {
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/bingo").setViewName("bingo");
registry.addViewController("/error").setViewName("error");
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new Loginintercepter()).
addPathPatterns("/**").
excludePathPatterns("/","/login","/login2","/login2/**","/logout","/testlog");
}
}
9、启动类:
package com.example.spbdemo01;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
//@MapperScan("com.example.spbdemo01.Dao") //启动类上添加注解扫描,否则spring中没有Daomapper接口
public class Spbdemo01Application {
public static void main(String[] args) {
SpringApplication.run(Spbdemo01Application.class, args);
}
}
10、日志的xml文件
注意其中的日志文件存放路径,本项目放在了:/Log4j日志位置/pht/realcaldemo/log下,即本项目文件的同级路径下。
其他内容基本是固定的,直接复制,spring-log4j2.xml:
<?xml version="1.0" encoding="UTF-8"?>
<!--Configuration后面的status,这个用于设置log4j2自身内部的信息输出,可以不设置,当设置成trace时,你会看到log4j2内部各种详细输出-->
<!--monitorInterval:Log4j能够自动检测修改配置 文件和重新配置本身,设置间隔秒数-->
<configuration monitorInterval="5">
<!--日志级别以及优先级排序: OFF > FATAL > ERROR > WARN > INFO > DEBUG > TRACE > ALL -->
<!--变量配置-->
<Properties>
<!-- 格式化输出:%date表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度 %msg:日志消息,%n是换行符-->
<!-- %logger{36} 表示 Logger 名字最长36个字符 -->
<property name="LOG_PATTERN" value="%date{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n" />
<!-- !!!!!!!!!! -->
<!-- !!!!!!!!!! -->
<!--自定义日志文件存储的路径-->
<property name="FILE_PATH" value="/Log4j日志位置/pht/realcaldemo/log" />
<property name="FILE_NAME" value="realcaldemo" />
</Properties>
<appenders>
<console name="Console" target="SYSTEM_OUT">
<!--输出日志的格式-->
<PatternLayout pattern="${LOG_PATTERN}"/>
<!--控制台只输出level及其以上级别的信息(onMatch),其他的直接拒绝(onMismatch)-->
<ThresholdFilter level="info" onMatch="ACCEPT" onMismatch="DENY"/>
</console>
<!--文件会打印出所有信息,这个log每次运行程序会自动清空,由append属性决定,适合临时测试用-->
<File name="Filelog" fileName="${FILE_PATH}/test.log" append="false">
<PatternLayout pattern="${LOG_PATTERN}"/>
</File>
<!-- 这个会打印出所有的info及以下级别的信息,每次大小超过size,则这size大小的日志会自动存入按年份-月份建立的文件夹下面并进行压缩,作为存档-->
<RollingFile name="RollingFileInfo" fileName="${FILE_PATH}/info.log" filePattern="${FILE_PATH}/${FILE_NAME}-INFO-%d{yyyy-MM-dd}_%i.log.gz">
<!--控制台只输出level及以上级别的信息(onMatch),其他的直接拒绝(onMismatch)-->
<ThresholdFilter level="info" onMatch="ACCEPT" onMismatch="DENY"/>
<PatternLayout pattern="${LOG_PATTERN}"/>
<Policies>
<!--interval属性用来指定多久滚动一次,默认是1 hour-->
<TimeBasedTriggeringPolicy interval="1"/>
<SizeBasedTriggeringPolicy size="10MB"/>
</Policies>
<!-- DefaultRolloverStrategy属性如不设置,则默认为最多同一文件夹下7个文件开始覆盖-->
<DefaultRolloverStrategy max="15"/>
</RollingFile>
<!-- 这个会打印出所有的warn及以下级别的信息,每次大小超过size,则这size大小的日志会自动存入按年份-月份建立的文件夹下面并进行压缩,作为存档-->
<RollingFile name="RollingFileWarn" fileName="${FILE_PATH}/warn.log" filePattern="${FILE_PATH}/${FILE_NAME}-WARN-%d{yyyy-MM-dd}_%i.log.gz">
<!--控制台只输出level及以上级别的信息(onMatch),其他的直接拒绝(onMismatch)-->
<ThresholdFilter level="warn" onMatch="ACCEPT" onMismatch="DENY"/>
<PatternLayout pattern="${LOG_PATTERN}"/>
<Policies>
<!--interval属性用来指定多久滚动一次,默认是1 hour-->
<TimeBasedTriggeringPolicy interval="1"/>
<SizeBasedTriggeringPolicy size="10MB"/>
</Policies>
<!-- DefaultRolloverStrategy属性如不设置,则默认为最多同一文件夹下7个文件开始覆盖-->
<DefaultRolloverStrategy max="15"/>
</RollingFile>
<!-- 这个会打印出所有的error及以下级别的信息,每次大小超过size,则这size大小的日志会自动存入按年份-月份建立的文件夹下面并进行压缩,作为存档-->
<RollingFile name="RollingFileError" fileName="${FILE_PATH}/error.log" filePattern="${FILE_PATH}/${FILE_NAME}-ERROR-%d{yyyy-MM-dd}_%i.log.gz">
<!--控制台只输出level及以上级别的信息(onMatch),其他的直接拒绝(onMismatch)-->
<ThresholdFilter level="error" onMatch="ACCEPT" onMismatch="DENY"/>
<PatternLayout pattern="${LOG_PATTERN}"/>
<Policies>
<!--interval属性用来指定多久滚动一次,默认是1 hour-->
<TimeBasedTriggeringPolicy interval="1"/>
<SizeBasedTriggeringPolicy size="10MB"/>
</Policies>
<!-- DefaultRolloverStrategy属性如不设置,则默认为最多同一文件夹下7个文件开始覆盖-->
<DefaultRolloverStrategy max="15"/>
</RollingFile>
</appenders>
<!--Logger节点用来单独指定日志的形式,比如要为指定包下的class指定不同的日志级别等。-->
<!--然后定义loggers,只有定义了logger并引入的appender,appender才会生效-->
<loggers>
<!--过滤掉spring和mybatis的一些无用的DEBUG信息-->
<logger name="org.mybatis" level="info" additivity="false">
<AppenderRef ref="Console"/>
</logger>
<!--监控系统信息-->
<!--若是additivity设为false,则 子Logger 只会在自己的appender里输出,而不会在 父Logger 的appender里输出。-->
<Logger name="org.springframework" level="info" additivity="false">
<AppenderRef ref="Console"/>
</Logger>
<root level="info">
<appender-ref ref="Console"/>
<appender-ref ref="Filelog"/>
<appender-ref ref="RollingFileInfo"/>
<appender-ref ref="RollingFileWarn"/>
<appender-ref ref="RollingFileError"/>
</root>
</loggers>
</configuration>
11、yaml配置文件:
存放了数据库信息,mapper信息和日志xml文件路径
spring:
datasource:
url: jdbc:mysql://localhost:3306/majinbuu1?serverTimezone=UTC
driver-class-name: com.mysql.cj.jdbc.Driver
password: 123456
username: root
mybatis:
mapper-locations: classpath:mapper/*.xml
type-aliases-package: com.example.spbdemo01.Pojo
logging:
config: classpath:spring-log4j2.xml
12、页面html文件:
check.html:(这里采用Post的方式提交表单)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>用户验证</title>
</head>
<body>
<header><h2>我的系统登录界面</h2></header>
<hr/>
<form role="form" action="/login2" method="post">
<strong>用户名:</strong> <input type="text" id="name" name="name" placeholder="输入您的用户名"><br>
<strong>密码:</strong> <input type="password" id="password" name="password" placeholder="输入您的密码"><br>
<p>
<input type="submit" id="login" value="登录">
<input type="reset" value="重置">
</p>
</form>
<hr/>
<footer>©版权归XXX所有</footer>
</body>
</html>
bingo.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>登录成功</h1>
<a href="/logout">退出登录</a>
</body>
</html>
index,html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>首页</title>
</head>
<body>
<h1>学生管理系统登录页面</h1>
</body>
</html>
error.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
验证无法通过!
</body>
</html>
13、报错:
之前springboot整合mybatis,报错:Invalid bound statement(not found)问题。
检查mapper.xm命名空间映射问题等后,仍然没有发现错误。折腾了几个小时后,终于发现问题:
我的yaml配置文件中的内容:
mybatis:
mapper-location: classpath:mapper/*.xml
type-aliases-package: com.example.spbdemo01.Pojo
mapper-location没有加s(我吐了),修改为:
mybatis:
mapper-locations: classpath:mapper/*.xml
type-aliases-package: com.example.spbdemo01.Pojo
问题解决。
14、其他问题:
@Getmapper与@Postmapper使用的区别,超链接一般用get,表单用post。
参考
15、效果如下:
点击退出登录或账号密码错误,会重定向到登录页面。
日志信息再控制台和日志文件都能查看,略。