SpringBoot + MybatisPlus
SpringBoot+Mybatis
jar包引入
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>1.3.0</version> </dependency>
配置文件
配置文件有两种方式properties或者yml,使用其中一个即可。
配置application.properties
如果是properties文件,配置如下
#Mybatis数据源配置 spring.datasource.url=jdbc:mysql://localhost:3306/demo?characterEncoding=utf8&characterSetResults=utf8&autoReconnect=true&failOverReadOnly=false spring.datasource.username=root spring.datasource.password=123456 spring.datasource.driver-class-name=com.mysql.jdbc.Driver
#Mybatis扫描配置(扫描POJO和XML配置)
mybatis.type-aliases-package=com.example.demo1.entity,com.example.demo2.entity
mybatis.mapperLocations=classpath:mappers/*.xml
配置application.yml
如果是yml文件,配置如下
spring: datasource: url: jdbc:mysql://localhost:3306/javaelec?useUnicode=true&characterEncoding=utf-8&useSSL=true&serverTimezone=UTC username: root password: root driver-class-name: com.mysql.jdbc.Driver mybatis: mapper-locations: classpath:com/javaelec/*/mapper/*Mapper.xml type-aliases-package: com.example.demo1.entity,com.example.demo2.entity
扫描Mapper接口
方法一:在启动类上加@MapperScan,用来扫描Mapper接口。
@MapperScan("com.javaelec") @SpringBootApplication public class WxApplication { public static void main(String[] args) { SpringApplication.run(WxApplication.class, args); } }
方法二:在mapper接口文件上加@Mapper注解
SpringBoot + Mybatis Plus
Mybatis Plus官网:https://baomidou.com/
新建项目
IDEA新建SpringBoot项目,JDK选择1.8,URL默认Default URL。
勾选Spring Web,
勾选Mysql Driver、Mybatis Framework,勾选完会自动添加Maven依赖;不勾选也可以,待会手动添加坐标。
添加后POM中自动添加如下坐标
pom.xml添加依赖
<properties> <java.version>1.8</java.version> </properties> <dependencies> <!--spring boot web工程--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- mysql-connector --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency> <!-- mybatis --> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>2.1.1</version> </dependency> <!-- mybatis-plus --> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.1.2</version> </dependency> <!-- mybatis-plus代码生成器 --> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-generator</artifactId> <version>3.3.1.tmp</version> </dependency> <!-- freemarker模板,自动生成代码时用 --> <dependency> <groupId>org.freemarker</groupId> <artifactId>freemarker</artifactId> <version>2.3.29</version> </dependency> <!--lombok--> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> </dependencies>
配置数据源
在application.properties添加如下内容
# Mysql驱动配置信息 spring.datasource.driverClassName=com.mysql.cj.jdbc.Driver spring.datasource.url=jdbc:mysql://localhost:3306/demo?characterEncoding=UTF-8&useSSL=false&allowPublicKeyRetrieval=true spring.datasource.username=root spring.datasource.password=root # mybatis扫描包 ## 扫描mybatis的pojo mybatis.type-aliases-package=com.autumn.demo.entity ## 扫描mybatis的xml mybatis.mapper-locations=classpath:mybatis/mapper/*.xml # mybatis plus扫描包,和Mybatis一致即可 ## 扫描mybatis plus的pojo mybatis-plus.type-aliases-package=com.autumn.demo.entity ## 扫描mybatis plus的xml mybatis-plus.mapper-locations=classpath:mybatis/mapper/*.xml
代码自动生成类
在配置好application.properties的Mysql数据源,maven中引入mybatis-plus-generator、freemarker后,即可运行此自动生成代码,会自动生成controller、service(继承了MP的ServiceImpl接口)、serviceImpl、Mapper(继承了MP的BaseMapper接口)、mapper.xml。
package com.autumn.helper; import com.baomidou.mybatisplus.core.toolkit.StringPool; import com.baomidou.mybatisplus.generator.AutoGenerator; import com.baomidou.mybatisplus.generator.InjectionConfig; import com.baomidou.mybatisplus.generator.config.*; import com.baomidou.mybatisplus.generator.config.po.TableInfo; import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy; import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine; import org.springframework.core.io.ClassPathResource; import org.springframework.core.io.Resource; import org.springframework.core.io.support.PropertiesLoaderUtils; import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.Properties; /** * 代码生成器配置 * 前置: 需要在application.properties中配置好Mysql配置 * */ public class MPCodeGeneratorHelper { //生成的位置 private static String ParentPackage = "com.autumn.system"; //作者 private static String Author = "秋雨"; // 数据库连接url private static String dbUrl; // 数据库驱动 private static String dbDriverName; //数据库连接名称 private static String dbUserName; //数据库连接密码 private static String dbPassword; public static void main(String[] args) { // 加载DB配置信息 loadDbProperty(); // 代码生成器 AutoGenerator mpg = new AutoGenerator(); // 全局配置 GlobalConfig gc = new GlobalConfig(); String projectPath = System.getProperty("user.dir"); gc.setOutputDir(projectPath + "/src/main/java"); gc.setAuthor(Author); gc.setOpen(false); mpg.setGlobalConfig(gc); // 数据源配置 DataSourceConfig dsc = new DataSourceConfig(); dsc.setUrl(dbUrl); dsc.setDriverName(dbDriverName); dsc.setUsername(dbUserName); dsc.setPassword(dbPassword); mpg.setDataSource(dsc); // 包配置 PackageConfig pc = new PackageConfig(); pc.setParent(ParentPackage); mpg.setPackageInfo(pc); // 自定义配置 InjectionConfig cfg = new InjectionConfig() { @Override public void initMap() { } }; // 自定义输出配置 List<FileOutConfig> focList = new ArrayList<>(); // 自定义配置会被优先输出 focList.add(new FileOutConfig("/templates/mapper.xml.ftl") { @Override public String outputFile(TableInfo tableInfo) { return projectPath + "/src/main/resources/mybatis/mapper/" + tableInfo.getEntityName() + "Mapper" + StringPool.DOT_XML; } }); cfg.setFileOutConfigList(focList); mpg.setCfg(cfg); // 配置模板 TemplateConfig templateConfig = new TemplateConfig(); templateConfig.setXml(null); mpg.setTemplate(templateConfig); // 策略配置 StrategyConfig strategy = new StrategyConfig(); strategy.setNaming(NamingStrategy.underline_to_camel); strategy.setColumnNaming(NamingStrategy.underline_to_camel); strategy.setEntityLombokModel(false); strategy.setRestControllerStyle(true); strategy.setControllerMappingHyphenStyle(true); strategy.setTablePrefix(pc.getModuleName() + "_"); mpg.setStrategy(strategy); mpg.setTemplateEngine(new FreemarkerTemplateEngine()); mpg.execute(); } /** * 加载数据量属性配置信息 */ private static void loadDbProperty(){ Properties props = null; try { Resource resource = new ClassPathResource("/application.properties");// props = PropertiesLoaderUtils.loadProperties(resource); } catch (IOException e) { e.printStackTrace(); } dbUrl = props.getProperty("spring.datasource.url",""); dbDriverName = props.getProperty("spring.datasource.driverClassName",""); dbUserName = props.getProperty("spring.datasource.username",""); dbPassword = props.getProperty("spring.datasource.password",""); } }
配置扫描Mapper接口
在启动类上加@MapperScan("com.autumn")注解,扫描包下的Mapper接口。
@SpringBootApplication @MapperScan("com.autumn") public class SpbootMpApplication { public static void main(String[] args) { SpringApplication.run(SpbootMpApplication.class, args); } }
编写Controller
因为service继承了IService接口,所以基本的增删改查可以省略。
@RestController @RequestMapping("/user") public class UserController { @Autowired private UserServiceImpl userService; @RequestMapping("/add") @ResponseBody private String add(){ User user = new User(); user.setName("哈迪斯"); user.setAge(24); user.setSex("男"); boolean result = userService.save(user); return result?"数据新增":"数据新增失败"; } @RequestMapping("/delete") @ResponseBody private String delete(){ return userService.removeById(1)?"数据删除成功":"数据删除失败"; } @RequestMapping("/update") @ResponseBody private String update(){ User user = userService.getById(1); user.setName("塞尔达"); return userService.updateById(user)?"数据更新成功":"数据更新失败"; } @RequestMapping("/query") @ResponseBody private String query(){ return userService.list().toString(); } }
启动后测试
LoginInterceptor登录验证拦截器
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; import java.io.IOException; import java.io.PrintWriter; public class LoginInterceptor implements HandlerInterceptor{ /** * 拦截器预处理 */ @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { //无需登录,允许访问的地址 String[] allowUrls =new String[]{"/front"}; //获取请求URI地址(不带ip端口项目名) String uri = request.getRequestURI(); for (String url : allowUrls) { if (uri.contains(url)) { return true; } } HttpSession session = request.getSession(); Object sessionUserinfo = session.getAttribute("CURR_USER"); //如果已经登录,不拦截 if(sessionUserinfo!=null){ return true; }else { //如果未登录,提示没有session System.out.println("后端拦截器,拦截访问"+uri);PrintWriter writer = null; response.setCharacterEncoding("UTF-8"); response.setContentType("text/html; charset=utf-8"); try { writer = response.getWriter(); writer.print("登录信息失效!"); } catch (IOException e) { } finally { if (writer != null) writer.close(); } return false; } } @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 { } }
然后在InterceptorConfig文件中添加
@Override protected void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new LoginInterceptor()).addPathPatterns("/**").excludePathPatterns("/*/login");; super.addInterceptors(registry); }
InterceptorConfig拦截器配置编码
import org.springframework.context.annotation.Configuration; import org.springframework.http.converter.HttpMessageConverter; import org.springframework.http.converter.StringHttpMessageConverter; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport; import java.nio.charset.StandardCharsets; import java.util.List; @Configuration public class InterceptorConfig extends WebMvcConfigurationSupport { @Override protected void addInterceptors(InterceptorRegistry registry) {
//拦截所有action,除了/*/login registry.addInterceptor(new LoginInterceptor()).addPathPatterns("/**").excludePathPatterns("/*/login"); super.addInterceptors(registry); } /** * 设置编码为UTF-8 * @param converters */ @Override protected void extendMessageConverters(List<HttpMessageConverter<?>> converters) { // 解决controller返回字符串中文乱码问题 for (HttpMessageConverter<?> converter : converters) { if (converter instanceof StringHttpMessageConverter) { ((StringHttpMessageConverter)converter).setDefaultCharset(StandardCharsets.UTF_8); } } } }
Mybatis Plus分页
开启MP分页插件
import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class MybatisPlusPaginationConfig { @Bean public PaginationInterceptor paginationInterceptor() { return new PaginationInterceptor(); } }
Controller文件中使用分页
@RequestMapping("/queryByPage") @ResponseBody private String queryByPage(HttpServletRequest request){ int pageIndex = Integer.parseInt(request.getParameter("pageIndex")); int pageSize = Integer.parseInt(request.getParameter("pageSize")); Page<User> page = userService.page(new Page<>(pageIndex, pageSize), null); //如果使用Mapper直接操作:IPage<User> userIPage = userMapper.selectPage(new Page<>(pageIndex,pageSize),null); return page.getRecords().toString(); }
集成redis
下载redis,运行redis-server.exe。
maven依赖
<!--redis--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency>
Redis配置
# Redis数据库索引(默认为0) spring.redis.database=0 # Redis服务器地址 spring.redis.host=127.0.0.1 spring.redis.port=6379 spring.redis.password= # 连接池最大连接数(使用负值表示没有限制) spring.redis.jedis.pool.max-active=200 # 连接池最大阻塞等待时间(使用负值表示没有限制) spring.redis.jedis.pool.max-wait=-1 # 连接池中的最大空闲连接 spring.redis.jedis.pool.max-idle=10 # 连接池中的最小空闲连接 spring.redis.jedis.pool.min-idle=0 # 连接超时时间(毫秒) spring.redis.timeout=1000
RedisTool工具类
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cache.annotation.CachingConfigurerSupport; import org.springframework.data.redis.connection.DataType; import org.springframework.data.redis.core.Cursor; import org.springframework.data.redis.core.ScanOptions; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.data.redis.core.ZSetOperations.TypedTuple; import org.springframework.stereotype.Component; import java.util.*; import java.util.concurrent.TimeUnit; /** * redis工具类 **/ @Component public class RedisTool { @Autowired private StringRedisTemplate stringRedisTemplate; /** * redis存值 * @param key * @param value */ public void set(String key, String value) { stringRedisTemplate.opsForValue().set(key, value); } /** * redis取值 * @param key * @return */ public String get(String key) { return stringRedisTemplate.opsForValue().get(key); } /** * redis移除值 * @param key * @return */ public boolean remove(String key) { return stringRedisTemplate.delete(key); } }
Controller测试
@RequestMapping("/redistest") @ResponseBody private String redistest(HttpServletRequest request){ String token = redisTool.get("token"); if (StringUtils.isEmpty(token)){ token = UUID.randomUUID().toString(); redisTool.set("token",token); return "token generate by UUID:" + token; }else { return "token by redis:"+token; } }
Log4j2日志
坐标
<!--spring boot web工程,排除自带的日志--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <version>2.6.2</version> <exclusions> <exclusion> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-logging</artifactId> </exclusion> </exclusions> </dependency> <!--lombok,用注解方式使用log4j--> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.22</version> <optional>true</optional> </dependency> <!--log4j2日志--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-log4j2</artifactId> <version>2.6.2</version> </dependency>
application.properties配置
在application.properties中加如下配置
logging.config=classpath:log4j2.properties
log4j2.properties
在resources下面新建log4j2.properties,内容如下
status = warn name = Log4j2 appender.console.type = Console appender.console.name = consoleLog appender.console.filter.threshold.type = ThresholdFilter appender.console.filter.threshold.level = info appender.console.layout.type = PatternLayout appender.console.layout.pattern = %m%n appender.console.target = System_out appender.rolling.type = File appender.rolling.name = fileLog appender.rolling.filter.threshold.type = ThresholdFilter appender.rolling.filter.threshold.level = warn appender.rolling.layout.type = PatternLayout appender.rolling.layout.pattern = %d-%m%n appender.rolling.append = true appender.rolling.fileName = D:\\logs\\info.log rootLogger.level = debug rootLogger.appenderRef.consolelogdemo.ref = consoleLog rootLogger.appenderRef.filelogdemo.ref = fileLog
使用Log4j
直接在类上使用lombok的@Slf4j注解,然后通过网页调用即可。
@RestController @RequestMapping("/user") @Slf4j public class UserController { @RequestMapping("/login") @ResponseBody private String login(HttpSession session){ log.trace("这是 trace 类型日志... {}","trace"); log.debug("这是 debug 类型日志... {}","debug"); log.info("这是 info 类型日志... {}","info"); log.warn("这是 warn 类型日志... {}","warn"); log.error("这是 error 类型日志... {}","error"); return "登录成功"; } }
遇到的问题
Invalid bound statement (not found)
启动后依然报错,发现编译后的文件不包括xml,需要在pom.xml中添加
<build> <resources> <resource> <directory>src/main/java</directory> <includes> <include>**/*.xml</include> </includes> </resource> <resource> <directory>src/main/resources</directory> <includes> <include>**/*</include> </includes> </resource> </resources> </build>