美文网首页
后端项目PogongChat:从0到1^技术准备

后端项目PogongChat:从0到1^技术准备

作者: 破弓 | 来源:发表于2019-05-02 14:17 被阅读0次

本文对应工程项目
本文参考教程

一.项目构建介绍

项目使用语言>Java
项目代码的组织模式>Maven
项目框架>SpringBoot
项目开发工具>IDEA

二.生成项目

由于使用Spring的项目配置复杂,有专门的网站为我们生成壳项目.

https://start.spring.io/
配置项目

配置项目时注意dependencies要加入'REST API'选项.然后点击下载项目

三.say Hello World

注意是import项目,不是open项目(写给我这样的Java小白)import流程

  • 1.建类AnyController

  • 2.加入以下代码

@RestController
@RequestMapping("/sayHelloWorld")
public class AnyController {

    @GetMapping
    public Map<String,Object> sayHelloWorld(){
        System.out.println("hello world!");
        Map<String,Object> result = new HashMap<>();
        result.put("pg_key","pg_value");
        return result;
    }

}
  • 3.命令行跑起项目

命令>mvn spring-boot:run

  • 4.本地访问
本地访问

四.增加自己要的配置项

新建application.yml文件,这个文件在后面的配置会用到.(用application.properties文件其实也是可以的,只是application.properties的书写会麻烦)

当然配置工作只要就是在application.yml和pom.xml加东西.

  • 0.时间戳返回
代码:

Map<String,Object> result = new HashMap<>();
result.put("pg_key1111","pg_value1111");
Calendar calendar = Calendar.getInstance();
calendar.set(2016,Calendar.OCTOBER,2,0,0);
result.put("pg_key2",calendar.getTime());
加入配置前

{"pg_key":"pg_value","pg_key2":"2016-10-01T16:00:57.555+0000"}
在application.yml内加入配置

spring:
  jackson:
    date-format: yyyy-MM-dd
    time-zone: GMT+8
    serialization:
      write-dates-as-timestamps: true  #使用数值timestamp表示日期,true时会忽略date-format
加入配置后
{"pg_key":"pg_value","pg_key2":1475337606386}
  • 1.热部署

A.pom.xml加依赖

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

B.打开自动build选项

打开自动build选项

报错>Error:Maven Resources Compiler: Maven project configuration required for module 'PogongChat' isn't available. Compilation of Maven projects is supported only if external build is started from an IDE.
遇到以上问题 要 Build>Rebuild Project.

然后改动项目里面的代码,就会立刻触发热部署.

  • 2.日志

A.application.yml内添加配置

logging:
  file: target/app.log
  level:
    ROOT: WARN
    com.pogong: TRACE

B.代码内添加使用

public class AnyController {
    private static final Log log = LogFactory.getLog(AnyController.class);
    @GetMapping
    public Map<String,Object> sayHelloWorld(){
        if (log.isTraceEnabled()){
            log.trace("sayHelloWorld 被调用了");
        }
    }
}
  • 3.连接数据库

A.pom.xml添加

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.25</version>
        </dependency>

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

B.application.yml添加

spring:
  datasource:
    url: jdbc:mysql://localhost:3306/jdbc_db?rewriteBatchedStatements=true&characterEncoding=utf8
    username: root
    password: 123456
    driver-class-name: com.mysql.jdbc.Driver

C.代码添加(class AnyController内)

    @Autowired
    private JdbcTemplate jdbcTemplate;

    @GetMapping("/connectDB")
    public int connectDB(){
        String sql = "select * from tv_series";
        List<Map<String, Object>> list =  jdbcTemplate.queryForList(sql);
        for (Map<String, Object> map : list) {

            System.out.println("pg see begin");
            System.out.println(map.getClass());
            System.out.println(map);
            System.out.println("pg see end");

            Set<Map.Entry<String, Object>> entries = map.entrySet( );
            if(entries != null) {
                Iterator<Map.Entry<String, Object>> iterator = entries.iterator( );
                while(iterator.hasNext( )) {
                    Map.Entry<String, Object> entry =(Map.Entry<String, Object>) iterator.next( );
                    Object key = entry.getKey( );
                    Object value = entry.getValue();
                    System.out.println("pg see>"+key+":"+value);
                }
            }

        }
        return 1;
    }

连接数据库可以用的工具库有很多,这里用的是JdbcTemplate.

本节参考链接

  • 4.应用Mybatis创建数据映射关系

第一,因为要加入Mybatis,建立数据映射关系.所以代码得向分层正规化靠拢一步.

我用的是:
Controller>Service>Dao>Pojo
的层级关系.

为什么是这样的层级关系,我现在还说不清楚.只能说一个大概:
Controller>Service 是 方法调用传递;
Dao 是 接口,不直接实现方法.Dao的接口会对应配置Dao的xml.
       Dao的xml内包含sql语句以及数据库键名与数据模型类属性的关系;
Pojo 是 数据模型类;

第二,由于Mybatis的接入方式多种多样,有高深(装逼)也有浅薄(朴实).这里为了更好的了解原理,会先浅薄的接入后高深的接入.

  • 4.1 Mybatis浅薄接入

浅薄接入只用到Controller>Dao>Pojo,这三层.

A.pom.xml添加

<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis</artifactId>
    <version>3.4.6</version>
</dependency>

B.加入mybatis的其他配置

mybaits-config.xml
jdbc.properties
mappers/AnyDao.xml

以上三项主要是mybaits-config.xml,其他两项是附属于mybaits-config.xml的.

mybaits-config.xml内容如下:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">

<configuration>

    <properties resource="jdbc.properties" />

    <!--配置加载的环境,可以配置多套环境,设置id名称,默认加载development环境-->
    <environments default="development">

        <environment id="development">
            <!--事务管理器-->
            <transactionManager type="JDBC"/>
            <!--数据源 连接池配置-->
            <dataSource type="POOLED">
                <property name="driver" value="${jdbc.driver}" />
                <property name="url" value="${jdbc.url}" />
                <property name="username" value="${jdbc.username}" />
                <property name="password" value="${jdbc.password}" />
            </dataSource>
        </environment>

    </environments>

    <!--配置SQL映射文件-->
    <mappers>
        <mapper resource="mappers/AnyDao.xml"/>
    </mappers>

</configuration>

mybaits-config.xml的内容其实很简单,就是将数据库的连接信息(即:jdbc.properties)包含了,再加上与Dao接口对应的Dao的xml的文件路径.

数据库的连接信息:

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/jdbc_db?rewriteBatchedStatements=true&characterEncoding=utf8
jdbc.username=root
jdbc.password=123456
Dao的xml
如上所述:Dao的xml内包含sql语句以及数据库键名与数据模型类属性的关系;

<?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.pogong.PogongChat.Dao.AnyDao">

    <resultMap id="TvSeriesResultMap" type="com.pogong.PogongChat.Pojo.AnyObj">
        <result column="season_count" property="seasonCount" />
        <result column="origin_release" property="originRelease" />
    </resultMap>

    <select id="getAll" resultMap="TvSeriesResultMap">
        select * from tv_series
    </select>

</mapper>

C.用起来

在Controller内加入代码

@GetMapping("/test_mybaits")
    public int test_mybaits() {

//        1.创建SqlSessionFactoryBuilder对象
        SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();

//        2.加载SqlMapConfig.xml配置文件
        InputStream inputStream = null;
        try {
            inputStream = Resources.getResourceAsStream("mybaits-config.xml");
        } catch (IOException e) {
            e.printStackTrace();
        }

//        3.创建SqlSessionFactory对象
        sqlSessionFactory = sqlSessionFactoryBuilder.build(inputStream);
        SqlSession sqlSession = sqlSessionFactory.openSession();

        AnyDao anyDao = sqlSession.getMapper(AnyDao.class);
        List<AnyObj> list = anyDao.getAll();
        for (AnyObj obj : list) {
            System.out.println("pg see");
            System.out.println(obj);
        }

        return 1;
    }

代码也比较简单:

1.创建SqlSessionFactoryBuilder对象;
2.加载SqlMapConfig.xml配置文件;
3.由SqlSessionFactoryBuilder创建SqlSessionFactory对象;
4.SqlSessionFactory对象获取SqlSession对象;
5.SqlSession对象加载Dao接口实现类,调用对应方法;

打完收工
  • 4.2 Mybatis高深的接入

之所以说4.1内Mybatis的接入比较浅薄是因为加载Dao的实现类每次都得明码进行.那么高深的方式是怎么做的呢?

A.pom.xml添加

<!--<dependency>-->
    <!--<groupId>org.mybatis</groupId>-->
    <!--<artifactId>mybatis</artifactId>-->
    <!--<version>3.4.6</version>-->
<!--</dependency>-->

<dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
    <version>1.3.2</version>
</dependency>       

删除原有org.mybatis的引用,加入org.mybatis.spring.boot的引用.

B.更改其他配置

mybaits-config.xml如下:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">

<configuration>

    <!-- 设置包扫描(别名) -->
    <typeAliases>
        <package name="com.pogong.PogongChat.Pojo"/>
    </typeAliases>

    <!--配置SQL映射文件-->
    <mappers>
        <mapper resource="mappers/AnyDao.xml"/>
    </mappers>

</configuration>

application.yml加入:

jdbc:
  url: jdbc:mysql://localhost:3306/jdbc_db?rewriteBatchedStatements=true&characterEncoding=utf8
  username: root
  password: 123456
  driver-class-name: com.mysql.jdbc.Driver

删除jdbc.properties

C.构建RootConfig

@Configuration
@MapperScan(basePackageClasses = {AnyDao.class})
@EnableTransactionManagement
public class RootConfig {

    //pg point1>数据库连接配置(读取的数据在application.yml内)
    @Value(value = "${jdbc.driver-class-name}")
    private String driver;
    @Value(value = "${jdbc.url}")
    private String url;
    @Value(value = "${jdbc.username}")
    private String userName;
    @Value(value = "${jdbc.password}")
    private String password;

    @Bean
    public DataSource getDataSource() {
        DataSource dataSource = new DriverManagerDataSource();
        ((DriverManagerDataSource) dataSource).setDriverClassName(driver);
        ((DriverManagerDataSource) dataSource).setUrl(url);
        ((DriverManagerDataSource) dataSource).setUsername(userName);
        ((DriverManagerDataSource) dataSource).setPassword(password);
        return dataSource;
    }

    //pg point2>Dao映射配置(读取的数据在有mybatis-config.xml内)
    @Value(value = "classpath:mybaits-config.xml")
    private Resource configLocation;

    @Bean(name="sqlSessionFactory")
    public SqlSessionFactoryBean sqlSessionFactory(DataSource dataSource) {
        SqlSessionFactoryBean ssfb = new SqlSessionFactoryBean();
        ssfb.setConfigLocation(configLocation);
        ssfb.setDataSource(getDataSource());
        return ssfb;
    }

    //pg point3>[getDataSource方法]和[sqlSessionFactory方法]启动时会被调用一回,后面就不再会被调用
}

RootConfig的作用也很明显就是:
构建数据库连接;
并为加载mybaits-config.xml的内容(mappers和typeAliases);mappers内是Dao接口对应的Dao的xml的文件路径;typeAliases内是数据模型类的路径;

RootConfig内的两个方法都只在启动时会被调用一回.具体用到什么高深的东西现在笔者还不得而知.

D.构建层级化调用

Mybatis浅薄接入:AnyController的代码内一步到位的完成数据库的读取与数据的返回;

而在本节的接入中是按照:AnyController>AnyService>AnyDao层级化调用的;
  • 5.校验前端传入的数据
对于前端的态度:

不要相信前端传过来的数据;
一定不要相信前端传过来的数据;
绝对不要相信前端传过来的数据;

在判断传入数据时,我们不可能重复的写一些冗余的判断代码,而是用校验库内写好的注解(校验库SpringBooty已经自带,可以直接使用).

A.数据模型类加注解

public class AnyObj {
    @Null private Integer id;
    @NotNull private String name;
    @Min(1) private int seasonCount;
    private Date originRelease;
    ......
}

代码如上:

@Null>这项前端一定不能传入
@NotNull>这项前端一定要传入
@Min(1)>这项前端传入一定要大于等于1

B.接受数据方法加注解

@PostMapping("/add_obj")
public int add_obj(@Valid @RequestBody AnyObj anyObj) {
    System.out.println("pg see add_obj");
    System.out.println(anyObj);
    return  1;
}

在接受前端数据方法的参数前加入@Valid才会对接受数据做数据模型类内部写好的校验.

注意:不写@Valid,数据模型类内部写好的校验注解是不起作用的.(@Valid>级联验证)

C.Postman测试

id前端不能传

以上仅用id前端不能传来举例,其他校验也是一样的,就不一一举例了.

D.校验分组

有的时候一个数据模型类内的多个字段会在不同的时机有不同的
校验规则(如:Person包含姓名,性别,手机号.注册用户时,用户可能是第一步先填入姓名+性别,第二步在填入手机号).

那么不同的时机就要应用不同的校验规则.校验注解为此提供了分组的功能.
public interface Groups {
    interface addStep1{}
    interface addStep2{}
}

------------------------------------------------------------------------------------

@Null(groups = {Groups.addStep1.class}) private Integer id;
@NotNull(groups = {Groups.addStep2.class}) private String name;
@Min(value = 1,groups = {Groups.addStep1.class,Groups.addStep2.class}) private int seasonCount;

------------------------------------------------------------------------------------

@PostMapping("/add_obj1")
public int add_obj1(@Validated({Groups.addStep1.class}) @RequestBody AnyObj anyObj) {
    System.out.println("pg see add_obj1");
    System.out.println(anyObj);
    return  1;
}

@PostMapping("/add_obj2")
public int add_obj2(@Validated({Groups.addStep2.class}) @RequestBody AnyObj anyObj) {
    System.out.println("pg see add_obj2");
    System.out.println(anyObj);
    return  1;
}

代码如上,
方法add_obj1就应用了校验分组1;
方法add_obj2就应用了校验分组2;

  • 6.缓存

  • 6.1 缓存注解

使用缓存,必须在启动类前加'@EnableCaching'

@EnableCaching
@SpringBootApplication
@MapperScan("com.pogong.PogongChat.Dao")
public class PogongChatApplication {
    public static void main(String[] args) {
        SpringApplication.run(PogongChatApplication.class, args);
    }
}
缓存的实践标注写在Service内.

@Service
public class AnyService {
    @Autowired
    private AnyDao anyDao;

    //加缓存
    @Cacheable(cacheNames="AnyObj",key="#id")
    public AnyObj getOneById(int id){
        System.out.println("pg see Service getOneById");
        return anyDao.getOneById(id);
    }

    //清除缓存
    @CacheEvict(cacheNames="AnyObj",key="#id")
    public void logicDelete(int id,String reason){
        System.out.println("pg see Service logicDelete");
        anyDao.logicDelete(id,reason);
    }
}

以上存删缓存的键为字符串"AnyObj::{id}".

  • 6.2 缓存工具>redis

以上用到了缓存,但存储是用的系统内存.这里介绍成型的缓存服务器redis.

A.本地装redis

brew install redis

B.项目加redis配置

pom.xml加

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
application.yml加

spring:
  cache:
    redis:
      time-to-live: 300s

  redis:
    host: 127.0.0.1
    port: 6379
    jedis:
      pool:
        max-active: 8
        max-wait: 10000
        max-idle: 10

C.加redis功能代码

首先明确我们是要将一个对象存进redis,而不是普通数据类型.所以要对redis进行配置,保证能存也能取对象.

@Configuration
public class RedisConfig {

    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        RedisTemplate<String, Object> template = new RedisTemplate<String, Object>();

        template.setConnectionFactory(redisConnectionFactory);
        template.setKeySerializer(new StringRedisSerializer());
        template.setValueSerializer(new GenericJackson2JsonRedisSerializer());
        template.setHashKeySerializer(new GenericJackson2JsonRedisSerializer());
        template.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());
        template.afterPropertiesSet();

        return template;
    }
}

以下是加+取+删缓存的操作.

@Autowired RedisTemplate<?, ?> redisTemplate;

public AnyObj getOneById(int id){
    String key = "AnyObj_"+id;
    @SuppressWarnings("unchecked")
    RedisTemplate<String, AnyObj> rt = (RedisTemplate<String, AnyObj>)redisTemplate;
    
    AnyObj anyObj = rt.opsForValue().get(key);//<获取缓存数据
    if(anyObj == null) {
        anyObj =  anyDao.getOneById(id);
        rt.opsForValue().set(key,anyObj);//<设置缓存数据
        Calendar c = Calendar.getInstance();
        c.add(Calendar.MINUTE, 5);
        rt.expireAt(key, c.getTime());
        System.out.println("set data to cache");
    }else {
        System.out.println("data form cache");
    }
    
    return anyObj;
}

public void logicDelete(int id,String reason){
    System.out.println("pg see Service logicDelete");
    RedisTemplate<String, AnyObj> rt = (RedisTemplate<String, AnyObj>)redisTemplate;
    String key = "AnyObj_"+id;
    rt.delete(key);//<删除缓存
    anyDao.logicDelete(id,reason);
}

D.注意

1.测试时,先要把redis打开,命令>redis-server;
2.redis在application.yml内已经设置了全局的缓存超时时间,如果想更加精确的控制缓存时间可以像上文一样用Calendar来控制;

相关文章

  • 后端项目PogongChat:从0到1^技术准备

    本文对应工程项目本文参考教程 一.项目构建介绍 二.生成项目 由于使用Spring的项目配置复杂,有专门的网站为我...

  • 开始做全栈---前端的碎碎念1.0

    1.开发背景 最近有一个新的前后端分离的项目需求,之前虽然有维护前后端分离的项目,但是自己没有从0到1的经验。从框...

  • Android项目开发从0到1技术精解

    下图总结了Android项目开发中需要用到的核心知识。 PS:知识点会持续更新,大家有啥建议也可私聊我,谢谢!

  • 凯尔后端项目结构

    项目地址 凯尔后端:https://github.com/Mrshenxh/Kayle 项目技术选型 项目后端技术...

  • 2018-01-30 转眼又一年

    17年,做了两个项目。蜜檬和蜜檬妈,从0到1,框架搭建,技术选型,技术攻坚,带人。17年,从8月到12月不懈的坚持...

  • 大文件传输方案

    1.项目背景 项目后端框架是springboot,后端与后端之间需要进行文件传输,这个文件大小从几兆到10G不等,...

  • 【部署篇】使用spring boot + vue 的java的开

    1、搭建前准备 2、下载后端代码到本地,打开application.yml,修改数据库信息 后端项目自带SQL脚本...

  • 从0到0,从0到1。

    昨天和一客户交流,听到这么一句话,我现在的阶段勉强算0到0的阶段,到那个1的阶段还没有看到,或者说并不知道那个1在...

  • Vue

    vue3.0项目从0到1 vue3.0项目从0到1-初始化项目[https://www.jianshu.com/p...

  • MongoDB技术从0到1+

    本文是陈仕在“青芒话生长”MongoDB征文比赛的获奖文章,下面我们一起来欣赏下。 前言 偶然机会看到mongo中...

网友评论

      本文标题:后端项目PogongChat:从0到1^技术准备

      本文链接:https://www.haomeiwen.com/subject/ptmumqtx.html