当前位置:首页 > Java技术 > springboot 简单企业项目环境搭建

springboot 简单企业项目环境搭建

2022年08月04日 17:43:35Java技术4

学习了springboot,百度了一篇企业项目搭建觉得很不错,参照学习了一篇。
这里给自己定一个该框架搭建完成的目标,如下
框架要求功能:

  • 处理http/json 请求
  • 日志记录
  • 持久化
  • 数据源,事务控制
  • 定时任务
  • 视图模版

搭建环境:

  • 编译器:idea 2016.2.4
  • Maven : maven3.0
  • JDK: java7
  • 系统: mac OS 10.10.4
  • 数据库: mysql5.6

搭建记录

  1. 新建maven应用(不需要web应用)
  2. 在pom中添加以下配置
<!-- Spring boot 父引用-->
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.4.0.RELEASE</version>
    </parent>

    <!-- Spring boot 核心web-->
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    </dependencies>
  1. 新建一个controller
@Controller
@EnableAutoConfiguration
public class TestBootController {
     

    @RequestMapping("/")
    @ResponseBody
    String home() {
     
    return "hello world";
    }

    public static void main(String[] args) throws Exception {
     
    SpringApplication.run(TestBootController.class, args);
    }
}

此时的项目目录结构是这样的
springboot 简单企业项目环境搭建 _ JavaClub全栈架构师技术笔记
启动main函数,可以看到控制台输出,非常简单明了
springboot 简单企业项目环境搭建 _ JavaClub全栈架构师技术笔记

  1. 端口默认是8080,启动log已经写了,访问后如图所示
    springboot 简单企业项目环境搭建 _ JavaClub全栈架构师技术笔记
  2. 在搭建了基础应用的基础上,想增加service层抽离控制层和业务层代码
//业务层接口
public interface TestInterFace {
     

    public int testInterFace();

    public User testUser();
}

//业务层接口实现
@Service
public class TestInterFaceImpl implements TestInterFace {
     
    @Override public int testInterFace() {
     
    return 0;
    }

    @Override public User testUser() {
     
    return new User();
    }
}

修改controller层代码

@Controller
@EnableAutoConfiguration
public class TestBootController {
     
    @Autowired
    private TestInterFace testInterFace;

    @RequestMapping("/num")
    @ResponseBody
    int home() {
     
    int i = testInterFace.testInterFace();
    return i;
    }
    @RequestMapping("/get")
    @ResponseBody User getUser() {
     
    return testInterFace.testUser();
    }

    public static void main(String[] args) throws Exception {
     
    SpringApplication.run(TestBootController.class, args);
    }

}

启动后抛异常

org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name ‘testBootController’:
 Unsatisfied dependency expressed through field ‘testInterFace’: No qualifying bean of type [com.kx.springboot.service.TestInterFace]
  found for dependency [com.kx.springboot.service.TestInterFace]: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {
     
  @org.springframework.beans.factory.annotation.Autowired(required=true)}; nested exception is 
  org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.kx.springboot.service.TestInterFace] 
  found for dependency [com.kx.springboot.service.TestInterFace]: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {
     @org.springframework.beans.factory.annotation.Autowired(required=true)}

相信大家对这种异常非常常见,注入失败,这时候问题来了,按照传统的方式,对注入进行检查。service层已经加了@service的注解,怎么还是注入失败了呢,想查看配置文件,发现springboot没有配置文件,那么他是怎么扫描注解的呢?

百度了一下才知道,springboot默认按照包顺序注入,所以在创建controller时service还没有注入,springboot不需要传统的xml配置扫描包,只需要添加注解@ComponentScan(basePackages={“com.kx.springboot.service”}),代码如下

@Controller
@EnableAutoConfiguration
@ComponentScan(basePackages={
     "com.kx.springboot.service"})//添加的注解
public class TestBootController {
     
    @Autowired
    private TestInterFace testInterFace;

    @RequestMapping("/num")
    @ResponseBody
    int home() {
     
    int i = testInterFace.testInterFace();
    return i;
    }
    @RequestMapping("/get")
    @ResponseBody User getUser() {
     
    return testInterFace.testUser();
    }

    public static void main(String[] args) throws Exception {
     
    SpringApplication.run(TestBootController.class, args);
    }

}

再次启动,成功,访问http://localhost:8088/get

{
     “username”:”username寇鑫123,”password”:”password寇鑫123}

这时候,又有一个问题,web应用都是多controller,这种启动方式一次只能启动一个controller,那么,怎么才能启动应用后访问多个controller,查阅springboot官方教程后,修改代码如下

  1. 增加 UserController
@Controller
@RequestMapping("user")
public class UserController {
     
    @Autowired
    private TestInterFace testInterFace;

    @RequestMapping("/get")
    @ResponseBody User getUser() {
     
    return testInterFace.testUser();
    }
}
  1. 修改原来 TestBootController
@Controller
@RequestMapping("test")
public class TestBootController {
     
    @Autowired
    private TestInterFace testInterFace;

    @RequestMapping("/num")
    @ResponseBody
    int home() {
     
    int i = testInterFace.testInterFace();
    return i;
    }

    @RequestMapping("/get")
    @ResponseBody User getUser() {
     
    return testInterFace.testUser();
    }
}
  1. 在包的最外层增加新的应用启动入口 —> Application
@EnableAutoConfiguration
@ComponentScan(basePackages={
     "com.kx.springboot"})
public class Application {
     
    public static void main(String[] args) throws Exception {
     
    SpringApplication.run(Application.class, args);
    }
}

可以看到,应用启动入口配置了扫描所有包。此时整个项目的结构如图所示
springboot 简单企业项目环境搭建 _ JavaClub全栈架构师技术笔记
4. 启动应用后访问
http://localhost:8080/test/get

{
     “username”:”username寇鑫123,”password”:”password寇鑫123}

http://localhost:8080/user/get

{
     “username”:”username寇鑫123,”password”:”password寇鑫123}

到此,符合处理http/json 的web框架已经搭建ok了

第一步处理http/json已经完成了,现在给我们的框架里加上日志记录的功能

要求:

  • 日志按天记录,自动生成当天的记录文件
  • 日志分级存储(info,error)

Springboot自带日志,所以我们现在直接在SpringBoot中添加日志

修改 TestController

@Controller
@RequestMapping("test")
public class TestBootController {
     
//增加日志
    private final Logger log = LoggerFactory.getLogger(TestBootController.class);

    @Autowired
    private TestInterFace testInterFace;

    @RequestMapping("/num")
    @ResponseBody
    int home() {
     
    int i = testInterFace.testInterFace();
    return i;
    }
    @RequestMapping("/get")
    @ResponseBody User getUser() {
     
    //打印日志
    log.info("TestBootController getUser info");
    return testInterFace.testUser();
    }
}

只增加了两行代码,现在启动尝试打印日志

访问 http://localhost:8080/test/get
springboot 简单企业项目环境搭建 _ JavaClub全栈架构师技术笔记
可以看到我们的日志已经打出来了,那么现在又有疑问了,这个日志只是打在控制台了,并没有生成文件,查询后发现默认日志如果要打印生成文件需要添加application.properties,而添加这个只可以打固定名称格式的日志,并不能灵活的配置,所以添加Springboot默认支持的logback作为标准日志输出

  1. 添加新的pom依赖
 <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-logging</artifactId>
</dependency>

在resource下添加logback配置文件logback.xml

首先配置按天生成日志,尝试日志文件打印输出

<?xml version="1.0" encoding="UTF-8"?>

<configuration debug="false">
    <!--定义日志文件的存储地址 勿在 LogBack 的配置中使用相对路径-->
    <property name="LOG_HOME" value="/Users/kx/Desktop" />
    <!-- 控制台输出 -->
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
            <pattern>%d{
     yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{
     50} - %msg%n</pattern>
        </encoder>
    </appender>
    <!-- 按照每天生成日志文件 -->
    <appender name="FILE"  class="ch.qos.logback.core.rolling.RollingFileAppender">
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!--日志文件输出的文件名-->
            <FileNamePattern>${
     LOG_HOME}/TestSpringBoot.log.%d{
     yyyy-MM-dd}.log</FileNamePattern>
            <!--日志文件保留天数-->
            <MaxHistory>30</MaxHistory>
        </rollingPolicy>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
            <pattern>%d{
     yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{
     50} - %msg%n</pattern>
        </encoder>
        <!--日志文件最大的大小-->
        <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
            <MaxFileSize>10MB</MaxFileSize>
        </triggeringPolicy>
    </appender>

    <!-- 日志输出级别 -->
    <root level="INFO">
        <appender-ref ref="STDOUT" />
        <appender-ref ref="FILE" />
    </root>
</configuration>

启动应用,尝试输出日志

访问 http://localhost:8080/test/get
springboot 简单企业项目环境搭建 _ JavaClub全栈架构师技术笔记
首先发现我们的日志不是彩色的了,不过还好日志打出来了,那么看看我们的文件有没有生成

//生成文件
-rw-r--r--  1 kx  staff   5117  3 30 22:19 TestSpringBoot.log.2017-03-30.log

//info 日志打印效果
2017-03-30 22:21:03.341 [http-nio-8080-exec-3] INFO  
com.kx.springboot.controller.TestBootController - TestBootController getUser info

OK,文件也完美的按照我们指定的路径生成了,并且文件命名方式按照配置的日期命名,日志打印的内容也按照配置的内容正确的打印了,现在配置info日志和error日志,区分info和error打出来的日志文件

修改 logback.log 增加新的error appender 修改原来的appender 为 info

<?xml version="1.0" encoding="UTF-8"?>
<!--
    Copyright 2010-2011 The myBatis Team
    Licensed under the Apache License, Version 2.0 (the "License");
    you may not use this file except in compliance with the License.
    You may obtain a copy of the License at
        http://www.apache.org/licenses/LICENSE-2.0
    Unless required by applicable law or agreed to in writing, software
    distributed under the License is distributed on an "AS IS" BASIS,
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    See the License for the specific language governing permissions and
    limitations under the License.
-->
<configuration debug="false">
    <!--定义日志文件的存储地址 勿在 LogBack 的配置中使用相对路径-->
    <property name="LOG_HOME" value="/Users/kx/Desktop" />
    <!-- 控制台输出 -->
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
            <pattern>%d{
     yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{
     50} - %msg%n</pattern>
        </encoder>
    </appender>

    <!--修改原来的 appender 为info-->
    <!-- 按照每天生成日志文件 -->
    <appender name="DAYINFO"  class="ch.qos.logback.core.rolling.RollingFileAppender">
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!--日志文件输出的文件名-->
            <FileNamePattern>${
     LOG_HOME}/TestSpringBoot_info.log.%d{
     yyyy-MM-dd}.log</FileNamePattern>
            <!--日志文件保留天数-->
            <MaxHistory>30</MaxHistory>
        </rollingPolicy>
        <!--这里设置日志级别为info-->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>error</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
            <pattern>%d{
     yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{
     50} - %msg%n</pattern>
        </encoder>
        <!--日志文件最大的大小-->
        <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
            <MaxFileSize>10MB</MaxFileSize>
        </triggeringPolicy>
    </appender>

    <!--新增加的error appender-->
    <appender name="DAYERROR"  class="ch.qos.logback.core.rolling.RollingFileAppender">
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!--日志文件输出的文件名-->
            <FileNamePattern>${
     LOG_HOME}/TestSpringBoot_error.log.%d{
     yyyy-MM-dd}.log</FileNamePattern>
            <!--日志文件保留天数-->
            <MaxHistory>30</MaxHistory>
        </rollingPolicy>
         <!--这里设置日志级别为error-->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>error</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
            <pattern>%d{
     yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{
     50} - %msg%n</pattern>
        </encoder>
        <!--日志文件最大的大小-->
        <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
            <MaxFileSize>10MB</MaxFileSize>
        </triggeringPolicy>
    </appender>

    <!-- 日志输出级别 -->
    <root level="INFO">
        <appender-ref ref="STDOUT" />
        <appender-ref ref="DAYINFO" />
        <appender-ref ref="DAYERROR" />
    </root>
</configuration>

启动应用后发现已经新增了两个日志文件,命名完全按照配置

-rw-r--r--  1 kx  staff      0  3 30 22:19 TestSpringBoot_error.log.2017-03-30.log
-rw-r--r--  1 kx  staff   5117  3 30 22:19 TestSpringBoot_info.log.2017-03-30.log

访问 http://localhost:8080/test/get

//info 日志打印效果
2017-03-30 22:21:03.341 [http-nio-8080-exec-3] INFO  
com.kx.springboot.controller.TestBootController - TestBootController getUser info

//error 日志打印效果
2017-03-30 22:21:03.342 [http-nio-8080-exec-3] ERROR 
com.kx.springboot.controller.TestBootController - TestBootController getUser error

我们发现error日志和info日志已经按照我们的要求已经打印到对应的文件中了,那么现在我们想解决一下控制台彩色输出的模块,刚好百度到了这里的代码(珍藏)

    <conversionRule conversionWord="clr" converterClass="org.springframework.boot.logging.logback.ColorConverter" />
    <conversionRule conversionWord="wex" converterClass="org.springframework.boot.logging.logback.WhitespaceThrowableProxyConverter" />
    <conversionRule conversionWord="wEx" converterClass="org.springframework.boot.logging.logback.ExtendedWhitespaceThrowableProxyConverter" />
    <!-- 彩色日志格式 -->
    <property name="CONSOLE_LOG_PATTERN" value="${CONSOLE_LOG_PATTERN:-%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}" />
    <!-- Console 输出设置 -->
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>${
     CONSOLE_LOG_PATTERN}</pattern>
            <charset>utf8</charset>
        </encoder>
    </appender>

看一下我们现在的logback日志总文件

<?xml version="1.0" encoding="UTF-8"?>
<!--
    Copyright 2010-2011 The myBatis Team
    Licensed under the Apache License, Version 2.0 (the "License");
    you may not use this file except in compliance with the License.
    You may obtain a copy of the License at
        http://www.apache.org/licenses/LICENSE-2.0
    Unless required by applicable law or agreed to in writing, software
    distributed under the License is distributed on an "AS IS" BASIS,
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    See the License for the specific language governing permissions and
    limitations under the License.
-->
<configuration>
    <!--定义日志文件的存储地址 勿在 LogBack 的配置中使用相对路径-->
    <property name="LOG_HOME" value="/Users/kx/Desktop" />


    <!-- 彩色日志 -->
    <!-- 彩色日志依赖的渲染类 -->
    <conversionRule conversionWord="clr" converterClass="org.springframework.boot.logging.logback.ColorConverter" />
    <conversionRule conversionWord="wex" converterClass="org.springframework.boot.logging.logback.WhitespaceThrowableProxyConverter" />
    <conversionRule conversionWord="wEx" converterClass="org.springframework.boot.logging.logback.ExtendedWhitespaceThrowableProxyConverter" />
    <!-- 彩色日志格式 -->
    <property name="CONSOLE_LOG_PATTERN" value="${CONSOLE_LOG_PATTERN:-%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}" />
    <!-- Console 输出设置 -->
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>${
     CONSOLE_LOG_PATTERN}</pattern>
            <charset>utf8</charset>
        </encoder>
    </appender>

    <!-- 不用彩色控制台输出 -->
    <!--<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">-->
        <!--<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">-->
            <!--&lt;!&ndash;格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符&ndash;&gt;-->
            <!--<pattern>%d{
     yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{
     50} - %msg%n</pattern>-->
        <!--</encoder>-->
    <!--</appender>-->
    <!-- 按照每天生成日志文件 -->
    <appender name="DAYINFO"  class="ch.qos.logback.core.rolling.RollingFileAppender">
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!--日志文件输出的文件名-->
            <FileNamePattern>${
     LOG_HOME}/TestSpringBoot_info.log.%d{
     yyyy-MM-dd}.log</FileNamePattern>
            <!--日志文件保留天数-->
            <MaxHistory>30</MaxHistory>
        </rollingPolicy>
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>info</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
            <pattern>%d{
     yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{
     50} - %msg%n</pattern>
        </encoder>
        <!--日志文件最大的大小-->
        <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
            <MaxFileSize>10MB</MaxFileSize>
        </triggeringPolicy>
    </appender>

    <appender name="DAYERROR"  class="ch.qos.logback.core.rolling.RollingFileAppender">
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!--日志文件输出的文件名-->
            <FileNamePattern>${
     LOG_HOME}/TestSpringBoot_error.log.%d{
     yyyy-MM-dd}.log</FileNamePattern>
            <!--日志文件保留天数-->
            <MaxHistory>30</MaxHistory>
        </rollingPolicy>
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>error</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
            <pattern>%d{
     yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{
     50} - %msg%n</pattern>
        </encoder>
        <!--日志文件最大的大小-->
        <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
            <MaxFileSize>10MB</MaxFileSize>
        </triggeringPolicy>
    </appender>

    <!-- 日志输出级别 -->

    <root level="INFO">
        <appender-ref ref="STDOUT" />
        <appender-ref ref="DAYERROR" />
        <appender-ref ref="DAYINFO" />
    </root>
</configuration>

再次运行项目,访问 http://localhost:8080/test/get
springboot 简单企业项目环境搭建 _ JavaClub全栈架构师技术笔记
我们的彩色日志已经有了,而且结构清晰,调试代码的时候简直神器啊

整合Mybatis

在众多orm框架中,我对mybatis最熟悉,所以我采用mybatis进行整合,对我们的orm框架,这里我们也提出几点要求

支持分页
curd接口抽象处理
事务控制
多数据源
在查阅了一些资料后,找到目前为止最简单的一种整合mybatis方式,这里贴出原始博客地址

http://blog.didispace.com/springbootmybatis/

参照大神的整合,我们的整合异常的顺利,贴出我们增加的代码

在pom中添加以下依赖

<dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
    <version>1.1.1</version>
</dependency>
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.21</version>
</dependency>

在application.properties 中增加以下配置

spring.datasource.url=jdbc:mysql://localhost:3306/test
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.driver-class-name=com.mysql.jdbc.Driver

表结构

Create Table: CREATE TABLE `userinfo` (
  `id` int(20) NOT NULL AUTO_INCREMENT,
  `username` varchar(20) DEFAULT NULL,
  `password` varchar(20) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8

编写dao层代码,新建UserDao 接口

@Mapper
public interface UserDao {
     
    @Select("SELECT * FROM USERINFO WHERE username = #{username}")
    UserInfo findByName(@Param("username") String username);

    @Insert("INSERT INTO USERINFO(username, password) VALUES(#{username}, #{password})")
    int insert(@Param("username") String name, @Param("password") String password);

}

在业务层增加对dao层接口的引用,修改TestInterFace,TestInterFaceImpl

public interface TestInterFace {
     

    public int testInterFace();

    public UserInfo testUser();

    public int insertUser(String username,String password);//新增的接口
}


@Service
public class TestInterFaceImpl implements TestInterFace {
     
    //引入dao层接口
    @Autowired UserDao userDao;
    @Override public int testInterFace() {
     
    return 0;
    }

    @Override public UserInfo testUser() {
     
    return new UserInfo();
    }

    //新增的接口实现
    @Override public int insertUser(String username,String password) {
     
    return userDao.insert(username,password);
    }
}

接下来修改我们的controller,提供对外的接口,修改UserController

@Controller
@RequestMapping("user")
public class UserController {
     
    @Autowired
    private TestInterFace testInterFace;

    @RequestMapping("/get")
    @ResponseBody UserInfo getUser() {
     
    return testInterFace.testUser();
    }

    //增加新的对外访问接口
    @RequestMapping("/add")
    @ResponseBody String add() {
     
        testInterFace.insertUser("username123寇鑫","password123寇鑫");
        return "插入成功";
    }
}

来测试一下我们的新接口,访问 http://localhost:8080/user/add
springboot 简单企业项目环境搭建 _ JavaClub全栈架构师技术笔记
看到浏览器已经正常返回了,接下来去数据库看看数据有没有实际插入

+----+-------------------+-------------------+
| id | username          | password          |
+----+-------------------+-------------------+
|  1 | username123寇鑫   | password123寇鑫   |
+----+-------------------+-------------------+

可以看到,在我们的表中,已经插入了一条数据,并且中文显示正常。但现在每次新加一个接口,都要对应的写一条sql,这样很麻烦,而且不利于开发,业务方不能专注于业务的开发,所以我们要抽象出来通用的curd接口,并且支付分页。

mybatis有很多成熟的分页插件以及通用接口插件,这里我们也采用目前较为成熟的方案,不必重复造轮子。

添加pom

 <!--分页插件-->
<dependency>
    <groupId>com.github.pagehelper</groupId>
    <artifactId>pagehelper</artifactId>
    <version>4.2.1</version>
</dependency>
<!--通用Mapper-->
<dependency>
    <groupId>tk.mybatis</groupId>
    <artifactId>mapper</artifactId>
    <version>3.3.9</version>
</dependency>

因为springboot 不需要设置xml,所以这里都采用注解和代码的形式注入插件

新建配置类

package com.kx.springboot.dao.mybatis;

import com.github.pagehelper.PageHelper;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.springframework.context.annotation.Bean;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;

import java.util.Properties;

/**
 * Created by kx on 17/4/2.
 */
public class MyBatisConfig {
     
    @Bean(name = "sqlSessionFactory")
    public SqlSessionFactory sqlSessionFactoryBean() {
     
    SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
//  bean.setDataSource(dataSource());

    bean.setTypeAliasesPackage("com.kx.springboot.bean");

    //分页插件设置
    PageHelper pageHelper = new PageHelper();
    Properties properties = new Properties();
    properties.setProperty("reasonable", "true");
    properties.setProperty("supportMethodsArguments", "true");
    properties.setProperty("returnPageInfo", "check");
    properties.setProperty("params", "count=countSql");
    pageHelper.setProperties(properties);

    //添加分页插件
    bean.setPlugins(new Interceptor[]{
     pageHelper});

    ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
    try {
     
        //基于注解扫描Mapper,不需配置xml路径
        //bean.setMapperLocations(resolver.getResources("classpath:mapper/*.xml"));
        return bean.getObject();
    } catch (Exception e) {
     
        e.printStackTrace();
        throw new RuntimeException(e);
    }
    }
}

新建配置扫描类

package com.kx.springboot.dao.mybatis;

import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import tk.mybatis.spring.mapper.MapperScannerConfigurer;

import java.util.Properties;

/**
 * Created by kx on 17/4/2.
 */
@Configuration
//必须在MyBatisConfig注册后再加载MapperScannerConfigurer,否则会报错
@AutoConfigureAfter(MyBatisConfig.class)
public class MyBatisMapperScannerConfig {
     
    @Bean
    public MapperScannerConfigurer mapperScannerConfigurer() {
     
    MapperScannerConfigurer mapperScannerConfigurer = new MapperScannerConfigurer();
    mapperScannerConfigurer.setSqlSessionFactoryBeanName("sqlSessionFactory");
    mapperScannerConfigurer.setBasePackage("com.kx.springboot.dao.mybatis");

    //初始化扫描器的相关配置,这里我们要创建一个Mapper的父类
    Properties properties = new Properties();
    properties.setProperty("mappers", "com.kx.springboot.dao.baseDao.MyMapper");
    properties.setProperty("notEmpty", "false");
    properties.setProperty("IDENTITY", "MYSQL");

    mapperScannerConfigurer.setProperties(properties);

    return mapperScannerConfigurer;
    }
}

新建对外暴露接口

package com.kx.springboot.dao.baseDao;

import tk.mybatis.mapper.common.Mapper;
import tk.mybatis.mapper.common.MySqlMapper;

/**
 * Created by kx on 17/4/2.
 */
public interface MyMapper<T> extends Mapper<T>, MySqlMapper<T> {
     
    //TODO
    //FIXME 特别注意,该接口不能被扫描到,否则会出错
}

现在,修改我们的dao层实现类,继承我们的通用接口

@Mapper
public interface UserDao extends MyMapper<UserInfo> {
     

}

在业务层中增加想要调用的方法

public interface TestInterFace {
     

    public int testInterFace();

    public UserInfo testUser();

    public int insertUser(UserInfo userInfo);

//新增加的方法
    List<UserInfo> selectALL();
}


@Service
public class TestInterFaceImpl implements TestInterFace {
     
    @Autowired UserDao userDao;
    @Override public int testInterFace() {
     
    return 0;
    }

    @Override public UserInfo testUser() {
     
    return new UserInfo();
    }

    @Override public int insertUser(UserInfo userInfo) {
     
    return userDao.insert(userInfo);
    }

    //新增加的实现
    @Override
    public List<UserInfo> selectALL(){
     
    return userDao.selectAll();
    }
}

看到我们在调用userDao时已经有了通用的单表查询方法。将新接口暴露给http,修改controller

@Controller
@RequestMapping("user")
public class UserController {
     
    @Autowired
    private TestInterFace testInterFace;

    @RequestMapping("/get")
    @ResponseBody UserInfo getUser() {
     
    return testInterFace.testUser();
    }

    @RequestMapping("/add")
    @ResponseBody String add() {
     
        UserInfo user = new UserInfo();
        user.setUsername("username123寇鑫");
        user.setPassword("password123寇鑫");
        testInterFace.insertUser(user);
        return "插入成功";
    }

//新增的接口方法
    @RequestMapping("/getall")
    @ResponseBody List<UserInfo> getall() {
     
        return testInterFace.selectALL();
    }
}

访问http://localhost:8080/user/getall

程序抛出异常

### Error querying database.  Cause: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Table 'ssmtest.user_info' doesn't exist
### The error may exist in com/kx/springboot/dao/UserDao.java (best guess)
### The error may involve defaultParameterMap
### The error occurred while setting parameters
### SQL: SELECT username,password  FROM user_info
### Cause: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Table 'ssmtest.user_info' doesn't exist
; bad SQL grammar []; nested exception is com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Table 'ssmtest.user_info' doesn't exist] with root cause

com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Table 'ssmtest.user_info' doesn't exist
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:57)
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
    at java.lang.reflect.Constructor.newInstance(Constructor.java:526)

从异常可以看出来,我们的表和我们查询数据库的字段没有映射起来,查询资料后发现原因是通用插件的问题,默认的字段中有下划线,我们需要手动指定映射

修改userinfo类

package com.kx.springboot.bean;

import javax.persistence.Column;
import javax.persistence.Table;

/**
 * Created by kx on 17/3/29.
 */
 //增加注解声明表名
@Table(name = "userinfo")
public class UserInfo {
     
    //增加注解声明字段名
    @Column(name = "username")
    private String username = "username寇鑫123";
    @Column(name = "password")
    private String password = "password寇鑫123";

    public String getUsername() {
     
    return username;
    }

    public void setUsername(String username) {
     
    this.username = username;
    }

    public String getPassword() {
     
    return password;
    }

    public void setPassword(String password) {
     
    this.password = password;
    }

    @Override public String toString() {
     
    return "User{" + "username='" + username + '\'' + ", password='" + password + '\'' + '}';
    }
}

再次启动访问 http://loclhost:8080/user/getall

[
    {
     
        "username":"user123寇鑫",
        "password":"password123寇鑫"
    },

    {
     
        "username":"username123寇鑫",
        "password":"password123寇鑫"
    }
]

得到如下结果,到此已经成功整合了通用mapper插件,现在加入定时任务测试
springboot 定时任务的启动和配置要简单很多,只需要增加一个注解即可

修改Application.java 启动类

@EnableAutoConfiguration
@ComponentScan(basePackages={
     "com.kx.springboot"})
@EnableScheduling//增加支持定时任务的注解
public class Application {
     
    public static void main(String[] args) throws Exception {
     
    SpringApplication.run(Application.class, args);
    }
}

新建定时任务类

@Component
public class SchedulingTest {
     
    private final Logger logger = LoggerFactory.getLogger(getClass());

    @Scheduled(cron = "0/5 * * * * ?") // 每5秒执行一次
    public void scheduler() {
     
    logger.info(">>>>>>>>>>>>> scheduled test... ");
    }
}

启动测试

2017-04-05 00:19:00.002  INFO 6512 --- 
[pool-1-thread-1] c.kx.springboot.schedul.SchedulingTest   : >>>>>>>>>>>>> scheduled test... 
2017-04-05 00:19:05.000  INFO 6512 --- 
[pool-1-thread-1] c.kx.springboot.schedul.SchedulingTest   : >>>>>>>>>>>>> scheduled test... 
2017-04-05 00:19:10.000  INFO 6512 --- 
[pool-1-thread-1] c.kx.springboot.schedul.SchedulingTest   : >>>>>>>>>>>>> scheduled test... 
2017-04-05 00:19:15.000  INFO 6512 --- 
[pool-1-thread-1] c.kx.springboot.schedul.SchedulingTest   : >>>>>>>>>>>>> scheduled test... 
2017-04-05 00:19:20.001  INFO 6512 --- 
[pool-1-thread-1] c.kx.springboot.schedul.SchedulingTest   : >>>>>>>>>>>>> scheduled test... 
2017-04-05 00:19:25.002  INFO 6512 --- 
[pool-1-thread-1] c.kx.springboot.schedul.SchedulingTest   : >>>>>>>>>>>>> scheduled test... 
2017-04-05 00:19:30.003  INFO 6512 --- 
[pool-1-thread-1] c.kx.springboot.schedul.SchedulingTest   : >>>>>>>>>>>>> scheduled test... 
2017-04-05 00:19:35.003  INFO 6512 --- 
[pool-1-thread-1] c.kx.springboot.schedul.SchedulingTest   : >>>>>>>>>>>>> scheduled test... 

可以看到我们的定时任务执行结果没有问题,接下来要在框架中增加多数据源以及事务控制。

最后感谢大神的博客,附上原路径:
https://blog.csdn.net/u013187139/article/details/68944972

作者:攀岩巨峰的程序猿
来源链接:https://blog.csdn.net/zhangyuliang6430/article/details/105834172

版权声明:
1、JavaClub(https://www.javaclub.cn)以学习交流为目的,由作者投稿、网友推荐和小编整理收藏优秀的IT技术及相关内容,包括但不限于文字、图片、音频、视频、软件、程序等,其均来自互联网,本站不享有版权,版权归原作者所有。

2、本站提供的内容仅用于个人学习、研究或欣赏,以及其他非商业性或非盈利性用途,但同时应遵守著作权法及其他相关法律的规定,不得侵犯相关权利人及本网站的合法权利。
3、本网站内容原作者如不愿意在本网站刊登内容,请及时通知本站(javaclubcn@163.com),我们将第一时间核实后及时予以删除。


本文链接:https://www.javaclub.cn/java/17266.html

标签: Exception
分享给朋友:

“springboot 简单企业项目环境搭建” 的相关文章

报org.mybatis.spring.MyBatisSystemException: nested exception is `***.ReflectionException解决方法!

错误描述: 1.数据库中表(se_seat)设计 字段 数据类型 seSeatId varchar seSeatName...

java 异常处理

java 异常处理

一:什么是异常  异常是程序中的一些错误,但并不是所有的错误都是异常,并且错误有时候是可以避免的。  比如说,你的代码少了一个分号,那么运行出来结果是提示是错误 java.lang.Error;如果你用System.out.println(11/0),那么你是因为你用0做了...

Mybatis报错org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.builder.Bu

Mybatis报错org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.builder.Bu

使用spring+Mybatis報錯org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.builder.BuilderException: Er...

java异常处理中的返回值

java异常处理中的返回值

项目github地址:bitcarmanlee easy-algorithm-interview-and-practice 欢迎大家star,留言,一起学习进步 1.try-catch中的返回值 java代码中,有各种各样的try-catch...

java异常详细讲解

一起学习 1. 异常机制 1.1 异常机制是指当程序出现错误后,程序如何处理。具体来说,异常机制提供了程序退出的安全通道。当出现错误后,程序执行的流程发生改变,程序的控制权转移到异常处理器。 1.2 传统的处理异常的办法是,函数返...

Java异常处理和设计

Java异常处理和设计

#cnblogs_post_body h2 { background: rgba(64, 108, 164, 1) !important; margin: 15px 0 !important; padding: 5px 0 5px 20px; border-radius: 4px !i...

Mybatis异常处理之MySQL Connector Java] will not be managed by Spring

Mybatis异常处理之MySQL Connector Java] will not be managed by Spring

很长时间没写后台代码有点生疏了,这不今天又出点小插曲,写个文章记录下。 由于要上传点数据到后台,顺手整了个mybatis+springmvc。在保存数据时出现了异常。 Creating a new SqlSession SqlSession [org.apache...

java mybatis org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.

org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.exceptions.PersistenceException: ### Error qu...

Java中的异常处理:何时抛出异常,何时捕获异常,何时处理异常?

Java中的异常处理:何时抛出异常,何时捕获异常,何时处理异常?

1.具体明确(异常类型) 2.提早抛出(1抛更具体的异常类型,2 更好的定位) 3.延迟捕获 (在能处理的时候捕获,而不是把它‘吃掉’ Java中的异常处理:何时抛出异常,何时捕获异常? 2017-06-07   1 异常分类...

SSM

org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.exceptions.TooManyResultsException: Expected one result (or...

发表评论

访客

◎欢迎参与讨论,请在这里发表您的看法和观点。