▶【SecKill】U1 项目框架搭建


?【SecKill】U1 项目框架搭建

一、SpringBoot环境搭建

1、新建Maven Project

【报错】Could not get the value for parameter encoding for plugin execution default-resources

原因:maven包无法下载下来

【解决方法】选中项目右键 → Maven → Update Proejct

等更新完就可以再启动项目试试(一般情况下网络顺畅稳定,此方法可行),如果还是不行就去网上找到对应版本jar下载下来的,手动放到maven指定文件夹里

2、在pom.xml中添加依赖

3、搭建 简易 的SpringBoot框架

(1)删除src/test/java测试类

(2)改包名

【注】SpringBoot是在SpringMVC的基础上,做了封装。

SpringBoot开发程序 = SpringMVC(controller调用service,service调用DAO 的分层结构开发)

(3)分层结构controller、service、dao

① controller

 ② service

③ dao

(4)测试Demo1:新建DemoController类,添加代码(官网Spring Quickstart Guide简易项目代码)

package com.kirin.miaosha.controller;

@Controller
@EnableAutoConfiguration
public class DemoController {
    @RequestMapping("/")
    @ResponseBody
    String home() {
        return "Hello World!";
    }
    
    public static void main(String[] args) throws Exception {
        SpringApplication.run(DemoController.class, args);
    }
}

 (5)运行测试

  成功!

4、测试Demo2

(1)在com.kirin.miaosha中新建class类:MainApplication.class

(2)将DemoController.java中的这2段放入MainApplication.class中

DemoController.java:

MainApplication.class:

package com.kirin.miaosha;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

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

(3)运行MainApplication.class

【注】运行新的Tomcat前,先按停止键,暂停之前正在运行的Tomcat

5、Controller中的方法:

(1)rest api json输出

【例】

新建com.kirin.miaosha.result包

在com.kirin.miaosha.result包下,新建Result类

在Result类中,定义变量code、msg、data

生成get()、set()方法

package com.kirin.miaosha.result;

public class Result { //:泛型(广泛的类型)
    private int code;
    private String msg;
    private T data;  //不知道data的类型,则定义为T,在类后声明,表示T为泛型
    
    //生成get、set方法
    public int getCode() {
        return code;
    }
    public void setCode(int code) {
        this.code = code;
    }
    public String getMsg() {
        return msg;
    }
    public void setMsg(String msg) {
        this.msg = msg;
    }
    public T getData() {
        return data;
    }
    public void setData(T data) {
        this.data = data;
    }
}

DemoController.java:

package com.kirin.miaosha.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import com.kirin.miaosha.result.Result;

@Controller
public class DemoController {
    @RequestMapping("/")
    @ResponseBody
    String home() {
        return "Hello World!";
    }
    
    //Controller中的方法:
    //1.rest api json输出
    //【例】com.kirin.miaosha.result包下Result类
    @RequestMapping("/hello")
    @ResponseBody
    String hello() {
        Result.success(data);
        return new Result(0,"success","helo,kirin");
    }
    
    @RequestMapping("/helloError")
    @ResponseBody
    String helloError() {
        Result.error(CodeMsg);
        return new Result(500102,"XXX");
        return new Result(500101,"XXX");
        return new Result(500100,"session失效");
    }
    
}

Result.java:

CodeMsg.java:

package com.kirin.miaosha.result;

public class CodeMsg {
    private int code;
    private String msg;
    
    //定义通用异常
    public static CodeMsg SUCCESS = new CodeMsg(0, "success");
    public static CodeMsg SERVER_ERROR = new CodeMsg(500100, "服务端异常");

    private CodeMsg(int code, String msg) {
        this.code = code;
        this.msg = msg;
    }
    
    //生成get、set方法(后来发现用不到set方法,删除)
    public int getCode() {
        return code;
    }
    public String getMsg() {
        return msg;
    }
}

Result.java:

package com.kirin.miaosha.result;

public class Result { //:泛型(广泛的类型)
    private int code;
    private String msg;
    private T data;  //不知道data的类型,则定义为T,在类后声明,表示T为泛型
    
    
    //com.kirin.miaosha.controller包下DemoController.java
    //成功时调用
    public static  Result success(T data){
        return new Result(data); //写完后报错:生成一个构造函数private Result(T data)
        
    }
    
    //失败时调用
    public static  Result error(CodeMsg cm){ //报错:自动生成CodeMsg.java类
        return new Result(cm); //写完后报错:生成一个构造函数private Result(CodeMsg cm)
    }
    
    //public static  Result success(T data)报错后,自动生成的构造函数
    private Result(T data) {
        this.code = 0; //成功
        this.msg = "success";
        this.data = data;
    }
    
    //public static  Result error(CodeMsg cm)报错后,自动生成的构造函数
    private Result(CodeMsg cm) {
        if(cm == null) {
            return;
        }
        this.code = cm.getCode();
        this.msg = cm.getMsg();  
    }

    
    //生成get、set方法(后来发现用不到set方法,删除)
    public int getCode() {
        return code;
    }public String getMsg() {
        return msg;
    }public T getData() {
        return data;
    }
}

DemoController.java:

package com.kirin.miaosha.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import com.kirin.miaosha.result.CodeMsg;
import com.kirin.miaosha.result.Result;

@Controller
public class DemoController {
    @RequestMapping("/")
    @ResponseBody
    String home() {
        return "Hello World!";
    }
    
    //Controller中的方法:
    //1.rest api json输出
    //【例】com.kirin.miaosha.result包下Result类
    @RequestMapping("/hello")
    @ResponseBody
    public Result  hello() {
        return Result.success("helo,kirin");
//        return new Result(0,"success","helo,kirin");
    } 
    
    @RequestMapping("/helloError")
    @ResponseBody
    public Result  helloError() {
        return Result.error(CodeMsg.SERVER_ERROR);
//        return new Result(500100,"session失效");
    }
    
}

运行MainApplication.java

  成功!

(2)前端页面

二、集成Thymeleaf(页面模板=JSP),Result结果封装

1、添加Thymeleaf依赖(前端=JSP)



  org.springframework.boot
  spring-boot-starter-thymeleaf

2、配置文件

spring.thymeleaf.cache=false
spring.thymeleaf.content-type=text/html
spring.thymeleaf.enabled=true
spring.thymeleaf.encoding=UTF-8
spring.thymeleaf.mode=HTML5
spring.thymeleaf.prefix=classpath:/templates/
spring.thymeleaf.suffix=.html

3、Result结果封装

(1)DemoController.java:

//U1-2 集成Thymeleaf(页面模板=JSP),Result结果封装
@RequestMapping("/thymeleaf")
public String Thymeleaf() { //返回页面模板
    return "hello";
    //在配置文件中配置hello的页面模板
}  

(2)在配置文件中配置hello的页面模板

① 新建templates文件夹

② 在配置文件中配置hello的页面模板:src/main/resources/templates/hello.html




    hello
    


  

③ 定义一个对象

//U1-2 集成Thymeleaf(页面模板=JSP),Result结果封装
@RequestMapping("/thymeleaf")
public String Thymeleaf(Model model) { //返回页面模板
    model.addAttribute("name","kirin"); //定义一个对象
    return "hello";
    //在配置文件中配置hello的页面模板:src/main/resources/templates/hello.html
}  

运行MainApplication.java

 成功!

【报错】Project configuration is not up-to-date with pom.xml. Select: Maven->Update Project... from the project context menu or use Quick Fix.

原因:项目的配置没有及时更新with这个pom.xml文件,所以更新一下配置文件即可。

三、集成Mybatis(数据库)+Druid

1、添加pom.xml依赖



    org.mybatis.spring.boot
    mybatis-spring-boot-starter
    1.3.1

2、添加配置mybatis

① 新建包domain:访问根数据库的表

② 在application.properties中添加配置mybatis

# mybatis
mybatis.type-aliases-package=com.kirin.miaosha.domain
mybatis.configuration.map-underscore-to-camel-case=true
mybatis.configuration.default-fetch-size=100
mybatis.configuration.default-statement-timeout=3000
mybatis.mapperLocations = classpath:com/kirin/miaosha/dao/*.xml

③ 在application.properties中添加配置druid(连接池)

# druid
spring.datasource.url=jdbc:mysql://localhost:3306/miaosha
spring.datasource.username=root
spring.datasource.password=12345
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.filters=stat
spring.datasource.maxActive=2
spring.datasource.initialSize=1
spring.datasource.maxWait=60000
spring.datasource.minIdle=1
spring.datasource.timeBetweenEvictionRunsMillis=60000
spring.datasource.minEvictableIdleTimeMillis=300000
spring.datasource.validationQuery=select 'x'
spring.datasource.testWhileIdle=true
spring.datasource.testOnBorrow=false
spring.datasource.testOnReturn=false
spring.datasource.poolPreparedStatements=true
spring.datasource.maxOpenPreparedStatements=20

④ 在application.properties中添加配置Mysql



    mysql
    mysql-connector-java


    com.alibaba
    druid
    1.0.5

⑤ 连接数据库

A.新建数据库miaosha

CREATE DATABASE `miaosha`;
USE `miaosha`;

B.新建数据库表user

C.新建user表对应的domain对象

package com.kirin.miaosha.domain;

public class User {
    private int id;
    private String name;
    
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
}

D.新建调用user表的接口UserDao

package com.kirin.miaosha.dao;

@Mapper
public interface UserDao {
    
    @Select("select * from user where id = #{id}")
    public User getById(@Param("id") int id);

}

E.新建UserService

package com.kirin.miaosha.service;

@Service
public class UserService {
    
    @Autowired
    UserDao userDao;
    
    public User getById(int id) {
        return userDao.getById(id);
    }
}

F.DemoController.java

在数据库插入1条记录

//U1-4 数据库测试:获取id
@Autowired
UserService userService;
    
@RequestMapping("/db/get")
@ResponseBody
public Result dbGet() {
    User user = userService.getById(1);
    return Result.success(user);
}

G.运行

 成功!

H.数据库测试2:事务

DemoController.java:

在UserDao.java写插入语句

UserService.java:

I. 运行

数据库中 id=2,name=2222 的记录没有插入,因为这是一条事务

若去掉事务标签,

数据库中 id=2,name=2222 的记录插入

四、集成Jedis+Redis安装+通用缓存Key封装

1、Linux服务器准备工作

(1)Navicat连接Linux服务器的MYSQL

(2)新建miaosha数据库

① 连接数据库

启动服务

systemctl start mysqld.service

登录

mysql -uroot -p

密码为空

② 新建数据库:create database 数据库名;

create database miaosha;

选择数据库:use 数据库名;

use miaosha;

在Navicat出现miaosha数据库

③ 新建数据库表user

在数据库插入1条记录

④ 修改application.properties中服务器地址

⑤ 运行

2、安装Redis

(1)安装包redis-4.0.2.tar.gz

(2)将安装包拉进root文件夹下

(3)解压

tar -zxvf redis-4.0.2.tar.gz

解压后,出现目录redis-4.0.2

移动该文件夹到 

mv redis-4.0.2 /usr/local/redis

(4)make

① 进入移动后的目录

② 用4个CPU make一下,可加快编译速度

make -j 4

make完成后,查看目录

③ 把编译完成的可执行文件添加到目录中

make install

 完成!

④ 修改 redis.conf 配置文件

查看 redis.conf 配置文件

vi redis.conf

⑤ 修改 redis.conf 配置文件

    按「i」:进入插入模式
    按「ESC」:从插入模式切换为命令行模式
    打 :w  保存文件但不退出vi
    打 :wq  保存文件并退出vi

A. 使其可以让所有服务器访问

B. 允许后台执行

⑥ 查看Redis服务器是否可以访问

运行Redis服务器

redis-server ./redis.conf

(5)执行 install_server.sh,生成系统服务

进入 utils 下

执行 install_server.sh,生成系统服务

./install_server.sh

3、集成Redis

(1)在pom.xml添加Jedis和Fastjson依赖



    redis.clients
    jedis

    


    com.alibaba
    fastjson
    1.2.38
    

(2)在application.properties配置Redis

#redis
redis.host=192.168.xx.xx
redis.port=6379
redis.timeout=3
redis.password=xxxxx
redis.poolMaxTotal=10
redis.poolMaxIdle=10
redis.poolMaxWait=3

(3)

① 新建redis包

② 新建RedisConfig.java,加入配置文件的参数和方法

③ 新建其余7个class类

BasePrefix.java:

package com.kirin.miaosha.redis;

public abstract class BasePrefix implements KeyPrefix{
    
    private int expireSeconds;
    
    private String prefix;
    
    public BasePrefix(String prefix) { //0代表永不过期
        this(0, prefix);
    }
    
    public BasePrefix( int expireSeconds, String prefix) {
        this.expireSeconds = expireSeconds;
        this.prefix = prefix;
    }
    
    public int expireSeconds() { //默认0代表永不过期
        return expireSeconds;
    }

    public String getPrefix() {
        String className = getClass().getSimpleName();
        return className+":" + prefix;
    }

}

KeyPrefix.java:

package com.kirin.miaosha.redis;

public interface KeyPrefix {
    
    public int expireSeconds(); //有效期
    
    public String getPrefix(); //前缀
    
}

MiaoshaUserKey.java:

package com.kirin.miaosha.redis;

public class MiaoshaUserKey extends BasePrefix{

    public static final int TOKEN_EXPIRE = 3600*24 * 2;
    private MiaoshaUserKey(int expireSeconds, String prefix) {
        super(expireSeconds, prefix);
    }
    public static MiaoshaUserKey token = new MiaoshaUserKey(TOKEN_EXPIRE, "tk");
}

OrderKey.java:

package com.kirin.miaosha.redis;

public class OrderKey extends BasePrefix {

    public OrderKey(int expireSeconds, String prefix) {
        super(expireSeconds, prefix);
    }

}

RedisPoolFactory.java:

package com.kirin.miaosha.redis;

@Service
public class RedisPoolFactory {

    @Autowired
    RedisConfig redisConfig;
    
    @Bean
    public JedisPool JedisPoolFactory() {
        JedisPoolConfig poolConfig = new JedisPoolConfig();
        poolConfig.setMaxIdle(redisConfig.getPoolMaxIdle());
        poolConfig.setMaxTotal(redisConfig.getPoolMaxTotal());
        poolConfig.setMaxWaitMillis(redisConfig.getPoolMaxWait() * 1000);
        JedisPool jp = new JedisPool(poolConfig, redisConfig.getHost(), redisConfig.getPort(),
                redisConfig.getTimeout()*1000, redisConfig.getPassword(), 0);
        return jp;
    }
    
}

RedisService.java:

package com.kirin.miaosha.redis;

@Service
public class RedisService {
    
    @Autowired
    JedisPool jedisPool;
    
    //获取当前对象
    public  T get(KeyPrefix prefix, String key, Class clazz) {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            //生成真正的key
            String realKey = prefix.getPrefix() + key;
            String str = jedis.get(realKey);
            T t = stringToBean(str, clazz); //将获取的值,从String类型转换成bean类型
            return t;
        }finally {
            returnToPool(jedis);
        }
    }
    
    //设置对象
    public  boolean set(KeyPrefix prefix, String key,  T value) {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            String str = beanToString(value); //将设置的值,从bean类型转换成String类型
            if(str == null || str.length() <= 0) {
                return false;
            }
            //生成真正的key
            String realKey = prefix.getPrefix() + key;
            int seconds = prefix.expireSeconds();
            if(seconds <= 0) {
                jedis.set(realKey, str);
            }else {
                jedis.setex(realKey, seconds, str);
            }
            return true;
        }finally {
            returnToPool(jedis);
        }
    }
    
    //判断key是否存在
    public  boolean exists(KeyPrefix prefix, String key) {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            //生成真正的key
            String realKey = prefix.getPrefix() + key;
            return jedis.exists(realKey);
        }finally {
            returnToPool(jedis);
        }
    }
    
    //将设置的值,从bean类型转换成String类型
    private  String beanToString(T value) {
        if(value == null) { //若空,直接返回
            return null;
        }
        Class<?> clazz = value.getClass();
        if(clazz == int.class || clazz == Integer.class) { //若是int类型,直接写入
            return ""+value;
        }else if(clazz == String.class) { //若是String类型,直接写入
            return (String)value;
        }else if(clazz == long.class || clazz == Long.class) { //若是long类型,直接写入
            return ""+value;
        }else {
            return JSON.toJSONString(value);
        }
    }
    
    //将获取的值,从String类型转换成bean类型
    @SuppressWarnings("unchecked")
    private  T stringToBean(String str, Class clazz) {
        if(str == null || str.length() <= 0 || clazz == null) { //若空,直接返回
            return null;
        }
        if(clazz == int.class || clazz == Integer.class) { //若是int类型,强转为int类型
            return (T)Integer.valueOf(str);
        }else if(clazz == String.class) { //若是String类型,直接输出
            return (T)str;
        }else if(clazz == long.class || clazz == Long.class) { //若是long类型,强转为long类型
            return (T)Long.valueOf(str);
        }else {
            return JSON.toJavaObject(JSON.parseObject(str), clazz);
        }
    }
    
    private void returnToPool(Jedis jedis) {
         if(jedis != null) {
             jedis.close();
         }
    }
}

UserKey.java:

package com.kirin.miaosha.redis;

public class UserKey extends BasePrefix{

    private UserKey(String prefix) {
        super(prefix);
    }
}

DemoController.java:

测试:

相关