博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
springboot + mybatis + gradle项目构建过程
阅读量:6905 次
发布时间:2019-06-27

本文共 20372 字,大约阅读时间需要 67 分钟。

1.从根据需求下载脚手架或者到GitHub上去搜索对应的脚手架项目,D_iao ^0^

• 文件目录如下(此处generatorConfig.xml 和 log4j2.xml文件请忽略,后续会讲解)

 

2.使用Mybatis代码自动构建插件生成代码

•  gradle 相关配置

// Mybatis 代码自动生成所引入的包compile group: 'org.mybatis.generator', name: 'mybatis-generator-core', version: '1.3.3'// MyBatis代码自动生成插件工具apply plugin: "com.arenagod.gradle.MybatisGenerator"configurations {    mybatisGenerator}mybatisGenerator {    verbose = true    // 配置文件路径    configFile = 'src/main/resources/generatorConfig.xml'}

•  generatorConfig.xml配置详解

location="C:\Users\pc\.gradle\caches\modules-2\files-2.1\mysql\mysql-connector-java\5.1.38\dbbd7cd309ce167ec8367de4e41c63c2c8593cc5\mysql-connector-java-5.1.38.jar"/>

以上配置中注意targetProject路径请填写绝对路径,避免错误,其中targetPackage是类所处的包路径(确保包是存在的,否则无法生成),也就相当于

•  代码生成

配置完成之后首先得在数据库中新建对应的表,然后确保数据库能正常访问,最后在终端执行gradle mbGenerator或者点击如下任务

成功之后它会生成model、mapper接口以及xml文件

3.集成日志

• gradle 相关配置

compile group: 'org.springframework.boot', name: 'spring-boot-starter-log4j2', version: '1.4.0.RELEASE'// 排除冲突configurations {    mybatisGenerator    compile.exclude module: 'spring-boot-starter-logging'}

当没有引入spring-boot-starter-log4j2包时会报错:java.lang.IllegalStateException: Logback configuration error detected Logback 配置错误声明

原因参考链接;

解决方案:排除依赖 spring-boot-starter-logging

what???

排除依赖之后使用的时候又报错:Failed to load class "org.slf4j.impl.StaticLoggerBinder" 加载slf4j.impl.StaticLoggerBinder类失败

原因参考链接:

解决方案:添加依赖 spring-boot-starter-log4j2 此包所依赖的包如下:

4.0.0
org.springframework.boot
spring-boot-starters
1.4.0.RELEASE
spring-boot-starter-log4j2
Spring Boot Log4j 2 Starter
Starter for using Log4j2 for logging. An alternative to spring-boot-starter-logging
http://projects.spring.io/spring-boot/
Pivotal Software, Inc.
http://www.spring.io
${basedir}/../..
org.apache.logging.log4j
log4j-slf4j-impl
org.apache.logging.log4j
log4j-api
org.apache.logging.log4j
log4j-core
org.slf4j
jcl-over-slf4j
org.slf4j
jul-to-slf4j

它依赖了 log4j-slf4j-impl ,使用的是log4j2日志框架。

这里涉及到log4j、logback、log4j2以及slf4j相关概念,那么它们是啥关系呢?unbelievable...相关知识如下:

slf4j、log4j、logback、log4j2 日志接口(slf4j) slf4j是对所有日志框架制定的一种规范、标准、接口,并不是一个框架的具体的实现,因为接口并不能独立使用,需要和具体的日志框架实现配合使用(如log4j、logback) 日志实现(log4j、logback、log4j2)log4j是apache实现的一个开源日志组件logback同样是由log4j的作者设计完成的,拥有更好的特性,用来取代log4j的一个日志框架,是slf4j的原生实现Log4j2是log4j 1.x和logback的改进版,据说采用了一些新技术(无锁异步、等等),使得日志的吞吐量、性能比log4j 1.x提高10倍,并解决了一些死锁的bug,而且配置更加简单灵活,官网地址: http://logging.apache.org/log4j/2.x/manual/configuration.html为什么需要日志接口,直接使用具体的实现不就行了吗?接口用于定制规范,可以有多个实现,使用时是面向接口的(导入的包都是slf4j的包而不是具体某个日志框架中的包),即直接和接口交互,不直接使用实现,所以可以任意的更换实现而不用更改代码中的日志相关代码。比如:slf4j定义了一套日志接口,项目中使用的日志框架是logback,开发中调用的所有接口都是slf4j的,不直接使用logback,调用是 自己的工程调用slf4j的接口,slf4j的接口去调用logback的实现,可以看到整个过程应用程序并没有直接使用logback,当项目需要更换更加优秀的日志框架时(如log4j2)只需要引入Log4j2的jar和Log4j2对应的配置文件即可,完全不用更改Java代码中的日志相关的代码logger.info(“xxx”),也不用修改日志相关的类的导入的包(import org.slf4j.Logger; import org.slf4j.LoggerFactory;) 使用日志接口便于更换为其他日志框架,适配器作用log4j、logback、log4j2都是一种日志具体实现框架,所以既可以单独使用也可以结合slf4j一起搭配使用)

到此我们使用的是Log4j2日志框架,接下来是配置log4j,具体配置详解如下:

????
[%d{yyyy-MM-dd HH:mm:ss.SSS}] - ${sys:PID} --- %c{1}: %m%n

到此我们就算是把日志集成进去了,可以在终端看到各种log,very exciting!!! 

4.集成MybatisProvider

• Why ?

    有了它我们可以通过注解的方式结合动态SQL实现基本的增删改查操作,而不需要再在xml中写那么多重复繁琐的SQL了

• Come on ↓

  First: 定义一个Mapper接口并实现基本操作,如下:

package com.springboot.mybatis.demo.mapper.common;import com.springboot.mybatis.demo.mapper.common.provider.AutoSqlProvider;import com.springboot.mybatis.demo.mapper.common.provider.MethodProvider;import com.springboot.mybatis.demo.model.common.BaseModel;import org.apache.ibatis.annotations.DeleteProvider;import org.apache.ibatis.annotations.InsertProvider;import org.apache.ibatis.annotations.SelectProvider;import org.apache.ibatis.annotations.UpdateProvider;import java.io.Serializable;import java.util.List;public interface BaseMapper
{ @InsertProvider(type = AutoSqlProvider.class, method = MethodProvider.SAVE) int save(T entity); @DeleteProvider(type = AutoSqlProvider.class, method = MethodProvider.DELETE_BY_ID) int deleteById(Id id); @UpdateProvider(type = AutoSqlProvider.class, method = MethodProvider.UPDATE_BY_ID) int updateById(Id id); @SelectProvider(type = AutoSqlProvider.class, method = MethodProvider.FIND_ALL) List
findAll(T entity); @SelectProvider(type = AutoSqlProvider.class, method = MethodProvider.FIND_BY_ID) T findById(T entity); @SelectProvider(type = AutoSqlProvider.class, method = MethodProvider.FIND_AUTO_BY_PAGE) List
findAutoByPage(T entity);}

其中AutoSqlProvider是提供sql的类,MethodProvider是定义好我们使用MybatisProvider需要实现的基本持久层方法,这两个方法具体实现如下:

package com.springboot.mybatis.demo.mapper.common.provider;import com.google.common.base.CaseFormat;import com.springboot.mybatis.demo.mapper.common.provider.model.MybatisTable;import com.springboot.mybatis.demo.mapper.common.provider.utils.ProviderUtils;import org.apache.ibatis.jdbc.SQL;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import java.lang.reflect.Field;import java.util.List;public class AutoSqlProvider {    private static Logger logger = LoggerFactory.getLogger(AutoSqlProvider.class);    public String findAll(Object obj) {        MybatisTable mybatisTable = ProviderUtils.getMybatisTable(obj);        List
fields = mybatisTable.getMybatisColumnList(); SQL sql = new SQL(); fields.forEach(field -> sql.SELECT(CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, field.getName()))); sql.FROM(mybatisTable.getName()); logger.info(sql.toString()); return sql.toString(); } public String save(Object obj) {
     ... return null; } public String deleteById(String id) {
     ... return null; } public String findById(Object obj) {
... return null; } public String updateById(Object obj) {
... return null; } public String findAutoByPage(Object obj) { return null; }}
package com.springboot.mybatis.demo.mapper.common.provider;public class MethodProvider {    public static final String SAVE = "save";    public static final String DELETE_BY_ID = "deleteById";    public static final String UPDATE_BY_ID = "updateById";    public static final String FIND_ALL = "findAll";    public static final String FIND_BY_ID = "findById";    public static final String FIND_AUTO_BY_PAGE = "findAutoByPage";}

注意:

1.如果你在BaseMapper中定义了某个方法一定要在SqlProvider类中去实现该方法,否则将报找不到该方法的错误

2.在动态拼接SQL的时候遇到一个问题:即使开启了驼峰命名转换,在拼接的时候依然需要手动将表属性转换,否则不会自动转换

3.在SqlProvider中的SQL log可以去除,因为在集成日志的时候已经配置好了

4.ProviderUtils是通过反射的方式拿到表的一些基本属性:表名,表属性

•  到这里MybatisProvider的基础配置已经准备好,接下去就是让每一个mapper接口去继承我们这个基础Mapper,这样所有的基础增删改查都由BaseMapper负责,如下:

package com.springboot.mybatis.demo.mapper;import com.springboot.mybatis.demo.mapper.common.BaseMapper;import com.springboot.mybatis.demo.model.User;import java.util.List;public interface UserMapper extends BaseMapper
{
}

这样UserMapper就不需要再关注那些基础的操作了,wonderful !!!

5. 整合JSP过程

• 引入核心包

compile group: 'org.springframework.boot', name: 'spring-boot-starter-web', version: '2.0.0.RELEASE'// 注意此处一定要是compile或者缺省,不能使用providedRuntime否则jsp无法渲染compile group: 'org.apache.tomcat.embed', name: 'tomcat-embed-jasper', version: '9.0.6'
providedRuntime group: 'org.springframework.boot', name: 'spring-boot-starter-tomcat', version: '2.0.2.RELEASE' // 此行代码是用于解决内置tomcat和外部tomcat冲突问题,若仅使用内置tomcat则无需此行代码

这是两个基本的包,其中spring-boot-starter-web会引入tomcat也就是我们常说的SpringBoot内置的tomcat,而tomcat-embed-jasper是解析jsp的包,如果这个包没有引入或是有问题则无法渲染jsp页面

• 修改Application启动类

@EnableTransactionManagement @SpringBootApplication public class Application extends SpringBootServletInitializer {         @Override    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {        setRegisterErrorPageFilter(false);        return application.sources(Application.class);    }    public static void main(String[] args) throws Exception {        SpringApplication.run(Application.class, args);    }}

注意:启动类必须继承SpringBootServletInitializer 类并重写configure方法

• 创建jsp页面(目录详情如下)

• 接下來就是配置如何去获取jsp页面了,有两中选择

一:通过在application.properties文件中配置

spring.mvc.view.prefix=/WEB-INF/views/spring.mvc.view.suffix=.jsp

然后创建controller(注意:在Spring 2.0之后如果要返回jsp页面必须使用@Controller而不能使用@RestController)

@Controller // spring 2.0 如果要返回jsp页面必须使用Controller而不能使用RestControllerpublic class IndexController {    @GetMapping("/")    public String index() {        return "index";    }}

二:通过配置文件实现,这样的话直接请求 http:localhost:8080/就能直接获取到index.jsp页面,省去了controller代码的书写

@Configuration@EnableWebMvcpublic class WebMvcConfig implements WebMvcConfigurer {// /static (or /public or /resources or /META-INF/resources    @Bean    public InternalResourceViewResolver viewResolver() {        InternalResourceViewResolver resolver = new InternalResourceViewResolver();        resolver.setPrefix("/WEB-INF/views/");        resolver.setSuffix(".jsp");        return resolver;    }    @Override    public void addViewControllers(ViewControllerRegistry registry) {        registry.addViewController("/").setViewName("index");    }   // 此方法如果不重写的话将无法找到index.jsp资源    @Override    public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {        configurer.enable();    }}

 

6.集成Shiro认证和授权以及Session

• shiro核心

认证、授权、会话管理、缓存、加密

集成认证过程

(1)引包(注:包是按需引用的,以下只是个人构建时候引用的,仅供参考↓)

// shiro    compile group: 'org.apache.shiro', name: 'shiro-core', version: '1.3.2' // 必引包,shiro核心包    compile group: 'org.apache.shiro', name: 'shiro-web', version: '1.3.2' // 与web整合的包    compile group: 'org.apache.shiro', name: 'shiro-spring', version: '1.3.2' // 与spring整合的包    compile group: 'org.apache.shiro', name: 'shiro-ehcache', version: '1.3.2' // shiro缓存

(2)shiro配置文件

@Configurationpublic class ShiroConfig {    @Bean(name = "shiroFilter")    public ShiroFilterFactoryBean shiroFilterFactoryBean() {        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();        //拦截器Map        Map
filterChainDefinitionMap = new LinkedHashMap
(); //配置不会被拦截的路径 filterChainDefinitionMap.put("/static/**", "anon"); //配置退出 filterChainDefinitionMap.put("/logout", "logout");      //配置需要认证才能访问的路径 filterChainDefinitionMap.put("/**", "authc");      //配置需要认证和admin角色才能访问的路径      filterChainDefinitionMap.put("user/**","authc,roles[admin]") //注意roles中的角色可以为多个且时and的关系,即要拥有所有角色才能访问,如果要or关系可自行写filter shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap); //配置登陆路径 shiroFilterFactoryBean.setLoginUrl("/login"); //配置登陆成功后跳转的路径 shiroFilterFactoryBean.setSuccessUrl("/index"); //登陆失败跳回登陆界面 shiroFilterFactoryBean.setUnauthorizedUrl("/login"); shiroFilterFactoryBean.setSecurityManager(securityManager()); return shiroFilterFactoryBean; } @Bean public ShiroRealmOne shiroRealmOne() { ShiroRealmOne realm = new ShiroRealmOne(); // 此处是自定义shiro规则 return realm; } @Bean(name = "securityManager") public DefaultWebSecurityManager securityManager() { DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); securityManager.setRealm(shiroRealmOne());      securityManager.setCacheManager(ehCacheManager());      securityManager.setSessionManager(sessionManager()); return securityManager; } @Bean(name = "ehCacheManager") // 将用户信息缓存起来 public EhCacheManager ehCacheManager() { return new EhCacheManager(); }
  @Bean(name = "shiroCachingSessionDAO") // shiroSession   public SessionDAO shiroCachingSessionDAO() {
  EnterpriseCacheSessionDAO sessionDao = new EnterpriseCacheSessionDAO();   sessionDao.setSessionIdGenerator(new JavaUuidSessionIdGenerator()); // SessionId生成器   sessionDao.setCacheManager(ehCacheManager()); // 缓存    return sessionDao;   }
  @Bean(name = "sessionManager")   public DefaultWebSessionManager sessionManager() {   DefaultWebSessionManager defaultWebSessionManager = new DefaultWebSessionManager();   defaultWebSessionManager.setGlobalSessionTimeout(1000 * 60);   defaultWebSessionManager.setSessionDAO(shiroCachingSessionDAO());   return defaultWebSessionManager;   }
}

自定义realm,继承了AuthorizationInfo实现简单的登陆验证

package com.springboot.mybatis.demo.config.realm;import com.springboot.mybatis.demo.model.Permission;import com.springboot.mybatis.demo.model.Role;import com.springboot.mybatis.demo.model.User;import com.springboot.mybatis.demo.service.PermissionService;import com.springboot.mybatis.demo.service.RoleService;import com.springboot.mybatis.demo.service.UserService;import com.springboot.mybatis.demo.service.impl.PermissionServiceImpl;import com.springboot.mybatis.demo.service.impl.RoleServiceImpl;import com.springboot.mybatis.demo.service.impl.UserServiceImpl;import org.apache.shiro.SecurityUtils;import org.apache.shiro.authc.*;import org.apache.shiro.authz.AuthorizationInfo;import org.apache.shiro.authz.SimpleAuthorizationInfo;import org.apache.shiro.realm.AuthorizingRealm;import org.apache.shiro.session.Session;import org.apache.shiro.subject.PrincipalCollection;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.beans.factory.annotation.Autowired;import java.util.ArrayList;import java.util.List;import java.util.stream.Collectors;public class ShiroRealmOne extends AuthorizingRealm {    private Logger logger = LoggerFactory.getLogger(this.getClass());    @Autowired    private UserService userServiceImpl;    @Autowired    private RoleService roleServiceImpl;    @Autowired    private PermissionService permissionServiceImpl;    //授权(这里对授权不做讲解,可忽略)    @Override    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {        logger.info("doGetAuthorizationInfo+" + principalCollection.toString());        User user = userServiceImpl.findByUserName((String) principalCollection.getPrimaryPrincipal());        List
roleList = roleServiceImpl.findByUserId(user.getId()); List
permissionList = roleList != null && !roleList.isEmpty() ? permissionServiceImpl.findByRoleIds(roleList.stream().map(Role::getId).collect(Collectors.toList())) : new ArrayList<>(); SecurityUtils.getSubject().getSession().setAttribute(String.valueOf(user.getId()), SecurityUtils.getSubject().getPrincipals()); SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo(); //赋予角色 for (Role role : roleList) { simpleAuthorizationInfo.addRole(role.getRolName()); } //赋予权限 for (Permission permission : permissionList) {
simpleAuthorizationInfo.addStringPermission(permission.getPrmName()); } return simpleAuthorizationInfo; }  // 认证 @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException { logger.info("doGetAuthenticationInfo +" + authenticationToken.toString()); UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken; String userName = token.getUsername(); logger.info(userName + token.getPassword()); User user = userServiceImpl.findByUserName(token.getUsername()); if (user != null) {
Session session = SecurityUtils.getSubject().getSession(); session.setAttribute("user", user); return new SimpleAuthenticationInfo(userName, user.getUsrPassword(), getName()); } else { return null; } }}

到此shrio认证简单配置就配置好了,接下来就是验证了

控制器

package com.springboot.mybatis.demo.controller;import com.springboot.mybatis.demo.common.utils.SelfStringUtils;import com.springboot.mybatis.demo.controller.common.BaseController;import com.springboot.mybatis.demo.model.User;import org.apache.shiro.SecurityUtils;import org.apache.shiro.authc.AuthenticationException;import org.apache.shiro.authc.UsernamePasswordToken;import org.apache.shiro.subject.Subject;import org.springframework.stereotype.Controller;import org.springframework.ui.Model;import org.springframework.web.bind.annotation.GetMapping;import org.springframework.web.bind.annotation.PostMapping;@Controllerpublic class IndexController extends BaseController{    @PostMapping("login")    public String login(User user, Model model) {        if (user == null || SelfStringUtils.isEmpty(user.getUsrName()) || SelfStringUtils.isEmpty(user.getUsrPassword()) ) {            model.addAttribute("warn","请填写完整用户名和密码!");            return "login";        }        Subject subject = SecurityUtils.getSubject();        UsernamePasswordToken token = new UsernamePasswordToken(user.getUsrName(), user.getUsrPassword());        token.setRememberMe(true);        try {            subject.login(token);        } catch (AuthenticationException e) {            model.addAttribute("error","用户名或密码错误,请重新登陆!");            return "login";        }        return "index";    }    @GetMapping("login")    public String index() {        return "login";    }}

login jsp:

<%--  Created by IntelliJ IDEA.  User: Administrator  Date: 2018/7/29  Time: 14:34  To change this template use File | Settings | File Templates.--%><%@ page contentType="text/html;charset=UTF-8" language="java" %>    登陆    
User Name:
User Password:
${warn} ${error}

index jsp:

<%--  Created by IntelliJ IDEA.  User: pc  Date: 2018/7/23  Time: 14:02  To change this template use File | Settings | File Templates.--%><%@ page contentType="text/html;charset=UTF-8" language="java" %>    Title    

Welcome to here!

正常情况分析:

1.未登录时访问非login接口直接跳回login页面

2.登陆失败返回账户或密码错误

3.未填写完整账户和密码返回请填写完整账户和密码

4.登陆成功跳转到index页面,如果不是admin角色则不能访问user/**的路径,其他可以正常访问

 

 

未完!待续。。。如有不妥之处,请提建议和意见,谢谢

 

 

转载地址:http://jjmdl.baihongyu.com/

你可能感兴趣的文章
《CLR via C#》读书笔记 之 类型基础
查看>>
EXt js 学习笔记总结
查看>>
Vue---父子组件之间的通信
查看>>
第八章:手工建库
查看>>
JavaScript语法
查看>>
js事件浏览器兼容
查看>>
获取贴吧对应页html及写入文件
查看>>
Entity Framework学习初级篇3--LINQ TO Entities
查看>>
android 相对布局
查看>>
SilverLight商业应用程序开发---学习笔记(9)
查看>>
MS DTC 无法正确处理DC升级/降级事件。MS DTC 将继续运行并使用现有的安全设置。...
查看>>
CAN总线基础
查看>>
第3课 QT的诞生和本质
查看>>
CentOS6.8下安装Docker
查看>>
JavaScript HTML Handlebars Template
查看>>
java.lang.NumberFormatException 错误及解决办法
查看>>
python:大量参数如何传递
查看>>
curl 跨域请求回来的json数据带有BOM 字符\ufeff,掉诡异的BOM \ufeff
查看>>
Javascript下的AJAX
查看>>
<c:out>标签中的escapeXML属性
查看>>