SpringBoot直接上手/前后端分离

418 阅读5分钟

基于SpringBoot开发企业应用

1.搭建企业应用开发环境

  • 应用架构:MVC架构
  • Vue实现前台开发 (侧重数据的展示,整体【美】)
  • 后台: SpringBoot(侧重提供数据访问的API接口)
  • ORM框架: MyBatis Plus
  • 数据源框架: Druid
  • 单元测试: junit
  • 构建工具: maven
  • JDK: 1.8
  • 可运行包 : jar

2.SpringBoot开发企业应用

2.1新建工程

image-20210122164410893

2.2 完整的配置文件

pom.xml

注:令配maven出现无法下载依赖的情况(偶尔出现)

在当前工程的pom文件里再配一遍国内远程仓库

<?xml version="1.0" encoding="UTF-8"?>
<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.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.4.2</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>cn.com.chinahitech</groupId>
    <artifactId>bjmarket</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>bjmarket</name>
    <description>Demo project for Spring Boot</description>
    <properties>
        <java.version>1.8</java.version>
    </properties>

    <!-- 配置国内maven仓库源 -->
    <repositories>
        <repository>
            <id>ali-maven</id>
            <url>http://maven.aliyun.com/nexus/content/groups/public</url>
            <releases>
                <enabled>true</enabled>
            </releases>
            <snapshots>
                <enabled>true</enabled>
                <updatePolicy>always</updatePolicy>
                <checksumPolicy>fail</checksumPolicy>
            </snapshots>
        </repository>

        <repository>
            <id>central</id>
            <name>Maven Repository Switchboard</name>
            <layout>default</layout>
            <url>http://repo1.maven.org/maven2</url>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </repository>
    </repositories>
    <!--配置项目依赖-->
    <dependencies>
        <!-- spring-boot-starter -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>

        <!-- spring boot web -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!--thymeleaf模板-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>

        <!-- spring-boot-devtools -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>

        <!-- lombok 实现实体类运行时添加构造器/setter/getter -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>

        <!--    json object对象支持    -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.71</version>
        </dependency>

        <!--   mybatis plus     -->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.3.0</version>
        </dependency>

        <!--    MySQL驱动    -->
        <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.18</version>
        </dependency>

        <!--    数据连接池 druid    -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.1.20</version>
        </dependency>

        <!--    代码生成器中使用freemarker    -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-freemarker</artifactId>
            <version>2.2.2.RELEASE</version>
        </dependency>

        <!--    代码自动生成工具 mybatis-plus    -->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-generator</artifactId>
            <version>3.3.0</version>
        </dependency>

        <!-- junit单元测试 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
    </dependencies>


    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

把资源文件中的application.properties改成application.yml

#默认时8080 可以修改端口
server:
  port: 8081
spring:
#别名
  application:
    name: market
  aop:
    proxy-target-class: true
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://192.168.0.104:3306/market?allowPublicKeyRetrieval=true&useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai&useSSL=false
    username: root
    password: ROOTroot_1
    druid:
      validation-query: SELECT 1 FROM DUAL
      #初始化分配连接数量
      initial-size: 10
      #10s后无操作就收回该连接
      min-idle: 10
      #同时最高能容纳200个连接
      max-active: 200
      min-evictable-idle-time-millis: 300000
      test-on-borrow: false
      test-while-idle: true
      time-between-eviction-runs-millis: 30000
      pool-prepared-statements: true
      max-open-prepared-statements: 100

mybatis-plus:
#要与java下的包名一致
  type-aliases-package: cn.com.chinahitech.bjmarket.*.entity
  global-config:
    db-config:
      id-type: auto
      logic-delete-field: flag
      logic-delete-value: 1
      logic-not-delete-value: 0
  configuration:
    map-underscore-to-camel-case: true
    cache-enabled: false
    jdbc-type-for-null: 'null'
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
#配置日志
logging:
  config:
    classpath: logback.xml


在资源文件夹中新建日志配置文件logback.xml

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <!--日志格式-->
    <property name="LOG_PATTERN"
              value="%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} -%msg%n" />

    <property name="LOG_LEVEL" value="INFO"/>

    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>${LOG_PATTERN}</pattern>
        </encoder>
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>${LOG_LEVEL}</level>
        </filter>
    </appender>

    <root level="${LOG_LEVEL}">
        <appender-ref ref="STDOUT" />
    </root>
</configuration>

2.3 将数据库导入linux

  • xftp上传
  • 新建空数据库
  • source命令初始化脚本

2.4使用代码自动生成工具

CodeGenerator

添加依赖、编写配置

网站:baomidou.com/guide/gener…

老师给的配置好的文件:放进util包里

package cn.com.chinahitech.bjmarket.util;

import com.baomidou.mybatisplus.core.exceptions.MybatisPlusException;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
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 java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

public class CodeGenerator {

    /**
     * <p>
     * 读取控制台内容
     * </p>
     */
    public static String scanner(String tip) {
        Scanner scanner = new Scanner(System.in);
        StringBuilder help = new StringBuilder();
        help.append("请输入" + tip + ":");
        System.out.println(help.toString());
        if (scanner.hasNext()) {
            String ipt = scanner.next();
            if (StringUtils.isNotBlank(ipt)) {
                return ipt;
            }
        }
        throw new MybatisPlusException("请输入正确的" + tip + "!");
    }

    public static void main(String[] args) {
        // 代码生成器
        AutoGenerator mpg = new AutoGenerator();

        // 全局配置
        GlobalConfig gc = new GlobalConfig();
        String projectPath = System.getProperty("user.dir");
        gc.setOutputDir(projectPath + "/src/main/java");
        gc.setAuthor("sunjie");
        gc.setOpen(false);
        mpg.setGlobalConfig(gc);

        // 数据源配置
        DataSourceConfig dsc = new DataSourceConfig();
        dsc.setUrl("jdbc:mysql://192.168.0.104:3306/market?allowPublicKeyRetrieval=true&useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai&useSSL=false");
        dsc.setDriverName("com.mysql.cj.jdbc.Driver");
        dsc.setUsername("root");
        dsc.setPassword("ROOTroot_1");
        mpg.setDataSource(dsc);

        // 包配置
        PackageConfig pc = new PackageConfig();
        pc.setModuleName(scanner("请输入模块名"));
        pc.setParent("cn.com.chinahitech.bjmarket");
        mpg.setPackageInfo(pc);

        // 自定义配置
        InjectionConfig cfg = new InjectionConfig() {
            @Override
            public void initMap() {
                // to do nothing
            }
        };

        // 如果模板引擎是 freemarker
        String templatePath = "/templates/mapper.xml.ftl";

        // 自定义输出配置
        List<FileOutConfig> focList = new ArrayList<>();
        // 自定义配置会被优先输出
        focList.add(new FileOutConfig(templatePath) {
            @Override
            public String outputFile(TableInfo tableInfo) {
                // 自定义输出文件名 , 如果你 Entity 设置了前后缀、此处注意 xml 的名称会跟着发生变化!!
                return projectPath + "/src/main/resources/mapper/" + pc.getModuleName()
                        + "/" + 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(true);
        strategy.setRestControllerStyle(true);
        strategy.setInclude(scanner("表名,多个英文逗号分割").split(","));
        strategy.setControllerMappingHyphenStyle(true);
        strategy.setTablePrefix("t_");
        mpg.setStrategy(strategy);
        mpg.setTemplateEngine(new FreemarkerTemplateEngine());
        mpg.execute();
    }

}

执行后:

image-20210122170232138

模块名是指自动生成的文件夹的名字。

表名是指涉及到的数据库表。

一般来说是一张表对应生成一个模块

自动生成:

image-20210122170403631

mapper层就是之前的Dao层

3.统计各大城市大数据工作岗位占比

image-20210122170555070

以上这张t_pie表,就是大数据分析完之后放在sql里的表

我们的目的,就是把这些数据,以json的格式从后台输出,供前台调用并展示。

通过以上代码生成等一系列操作,我们已经把后台的框架搭建好,剩下的就时完善代码了。

3.1不是前后台分离

同一个项目里既有前台,又有后台

后台

entity层和mapper层生成的很好,我们不用动。

我们需要完善的就是service层和 controller层。

controller层调用service层,service层调用mapper层,mapper层访问数据库

service层

service层调用mapper层。

【接口】

public interface IPieService extends IService<Pie> {
    /**
     * 查询各城市所有的大数据岗位信息
     * @return
     */
    List<Pie> getCityDatas();

}

【实现】

@Service
public class PieServiceImpl extends ServiceImpl<PieMapper, Pie> implements IPieService {
    @Resource
    private PieMapper pieMapper;

    @Override
    //访问数据库,执行查询
    public List<Pie> getCityDatas() {
        //1 封装QueryWrapper对象
        QueryWrapper<Pie> wrapper=new QueryWrapper<>();
        //2 执行查询
        List<Pie> pieList=pieMapper.selectList(wrapper);
        return pieList;
    }
}

controller层

controller层调用service层

@RestController
@RequestMapping("/pie")
public class PieController {
    @Resource
    private IPieService pieService;
    
    @RequestMapping(value = "/getCityData")
    @ResponseBody
    public String getCityData(){
        Map<String,Object> map=new HashMap<>();
        try {
            // 1 调用service层执行查询
            List<Pie> cityDatas = pieService.getCityDatas();
            
            //2 执行成功 封装数据
            map.put("status","200");
            map.put("data",cityDatas);
        }catch (Exception e){
            //2 执行失败封装数据
            map.put("status","500");
            map.put("errorMsg","出错:"+e.getMessage());
        }
        
        //把刚刚封装好的返回出去,返回成jason数据
        return JSON.toJSONString(map);
       
    }

}

修改主类

现在的主类是:image-20210122174731484

@SpringBootApplication
@MapperScan("cn.com.chinahitech.bjmarket.*.mapper")//要添加扫包声明,扫描所有的mapper,就是dao包
public class BjmarketApplication {

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

}

运行

启动成功,端口是8081。后台的目的就是得到json数据

image-20210122191533626

就相当于我提供一个地址:http://localhost:8081/pie/getCityData (接口)

你调用这个地址就能得到相应的json数据

前台展示

模板页面:放到template下

需要通过Controller调用

配置static下的js

  • 将pie.html放到template目录下

  • js文件放到static目录下

    resource目录下的static目录下新建js,把js文件放进去

image-20210122194052771

controller改为展示页面

@Controller
@RequestMapping("/pie")
public class PieController {
    //省略现有代码
    @RequestMapping(value="/show")
    public String show(){
        return "pie"; //pie 是pie.html页面的名字
    }
    

}

测试之前记得先把上次生成的target删一下,不然会执行以前的代码。****

测试结果:

image-20210122194325864

3.2前后台分离

进行前后台分离的话,那么刚才的template目录下的页面、以及static目录下的js都不需要。

就是说上面的项目不做前台有关的任何内容,就是一个纯后台,意义就是给你一个地址,你可以从中得到数据。

那么前台的开发人员就可以用webstorm,创建一个前台项目。

最后编译也会得到这样一个文件

image-20210122211257833 image-20210122211408011
  • 后端程序:bjmarket (SpringBoot+MyBatis Plus)——IDEA
  • 前端程序:piesite(Vue基于ajax实现)——WebSTORM

解决跨域访问的问题

不再同一个项目里面 不跨域就是同一个ip同一个端口

单独执行pie.html

image-20210122212019534

没有出现饼图。

如何解决

在后端程序的controller解决

在controller类上面添加跨域访问的注解 @CrossOrigin

image-20210122212516959

异常就是origin的问题

@Controller
@RequestMapping("/pie")
@CrossOrigin   <-----------------添加注解-------->
public class PieController {
    @Resource
    private IPieService pieService;

    @RequestMapping(value = "/getCityData")
    @ResponseBody
    public String getCityData(){
        Map<String,Object> map=new HashMap<>();
        try {
        ...

重新启动服务

注:关于端口被占用的问题

在命令窗口输入命令:netstat -ano | findstr 8080(8080改成自己被占用的 端口),

然后输入结束进程的命令 :taskkill /pid 14076 /f 一个一个关掉进程。这个方法比较麻烦,下面介绍简单的。

image-20210122213219151

测试结果

image-20210122213303113

部署

SpringBoot后台程序打包--jar

image-20210122213519026

双击package(打包之前可能要把test文件夹里面的java文件删掉,不然可能会出错)

image-20210122214109461