(当前开源个人项目正在开发,请关注个人项目专栏。需要源码请关注留言哦!!!)
(怀玉是一名一年的后端,前端目前不太精通,前端代码是直接写好的)
首先我们先看一张图:
这大概就是我需要写的效果一部分,接下来我会介绍一下股票的一些基础知识。
注意:
一、概念介绍
1.1什么是股票:
股票是股份公司发给股东证明其所入股份的一种有价证券(有效凭证),它可以作为买卖对象和抵押品,是资金市场中主要的信用工具之一。
1.2股票的分类
A股:★★★
即人民币普通股票,是由中国境内注册公司发行,在境内上市,以人民币标明面值,供境内机构、组织或个人(2013年4月1日起,境内港澳台居民可开立A股账户)以人民币认购和交易的普通股股票。
英文字母A没有实际意义,只是用来区分人民币普通股票和人民币特种股票。
A股中的股票分类:
-绩优股:绩优股就是业绩优良公司的股票;
-垃圾股:与绩优股相对应,垃圾股指的是业绩较差的公司的股票;
-蓝筹股:指在其所属行业内占有重要支配性地位业绩优良成交活跃、红利优厚的大公司股票;
B股:
也称为人民币特种股票。是指那些在中国大陆注册、在中国大陆上市的特种股票。以人民币标明面值,只能以外币认购和交易;部分股票也开放港元交易;
H股:
也称为国企股,是指国有企业在香港 (Hong Kong) 上市的股票;
N股:
是指那些在中国大陆注册、在纽约(New York)上市的外资股;
SCA股:
是指那些主要生产或者经营等核心业务在中国大陆、而企业的注册地在新加坡(Singapore)或者其他国家和地区,但是在新加坡交易所上市挂牌的企业股票;
1.3股票核心参数介绍
开盘价:
是指证券交易所在每个交易日开市后的第一笔股票买卖成交的价格; 中国股市的开盘价格是由市场集合竞价所产生的。
在A股市场中,股票的开盘价是由集合竞价的9点15分至9点25分买卖双方的撮合,股票价格在有效价格范围内选取成交量最大的价位所产生的,也是证券交易所每个交易日开市后的第一笔每股买卖成交价格。如果集合竞价的时间内股票没有买卖或没有成交,则股票前一日的收盘价作为当日股票的开盘价。
一般状况:开盘参考价=前一买卖日收盘价。
收盘价:
又称收市价,是指某只股票在证券交易所每个交易日里的【最后一笔买卖成交价格】; 如果某只股票当日没有成交,则采用最近一次的成交价作为收盘价;
涨跌值:
当前股票的价格与前一天的收盘价比价,来反应股票的实时涨跌情况; 计算公式为:最新价格-前收盘价格
注意:一般在交易台上用“+”或“-”号表示,单位是元,正值为涨,负值为跌,否则为持平;
涨跌幅:
是对涨跌值的描绘; 计算公式为:股票涨跌幅计算公式:(最新成交价-前收盘价)÷前收盘价×100% 也就是(涨跌值)÷前收盘价×100%
涨停与跌停:
就是一种对股市涨跌幅的限制;
证券交易所为了抑制过度投机行为,防止市场出现过分的暴涨暴跌,强制约定在每天的交易中股票的涨跌幅必须在规定的区间内上下波动。如果股票价格上升到该限制幅度的最高限价为涨停板,而下跌至该限制幅度的最低限度为跌停板。
1、涨停指的是价格涨到一定幅度,价格会被限制,不再变动,但是可以继续交易。
2、跌停指的是价格跌到一定幅度,价格会被限制,不在变动,但是可以继续交易。
3、在中国A股市场,均设有涨幅和跌幅的限制,他们都是【涨跌幅10%】的限制,即所谓的涨停和跌停。 注意事项: 涨停和跌停适用中国所有A股,但是对于第一次上市交易股票当天是没有涨停限制的,第二天才有限制(打新);
股票交易采用T+1机制,也就是当日买进,那么最快第二个交易日才可卖出;
振幅:
股票振幅是指股票开盘后的当日最高价和最低价之间的差的绝对值与昨日收盘价的百分比,它在一定程度上表现股票的活跃程度。
计算公式为:(当日最高价-当日最低价)÷ 前收盘价 ×100%
成交量:
成交量指当天成交的股票总手数(1手=100股); 计算则是由交易所直接进行计算;
成家金额:
股票成交额是指某一特定时期内,成交某种股票的金额,其单位以人民币"元"计算; 成交金额就是每股价格乘交易的手数,再乘上100。
例如:投资者以每股10元的价格买入50手,10X50X100=50000,此时的5万就是成交额。
注意:
成交总金额又称总额,总额是指当天开盘以来总成交金额,单位以人民币"元"计算。
简单的说,这个总金额是反应当日有多少资金进行了成交操作。
股票编码:
1、创业板 :创业板的代码是300打头的股票代码;
2、沪市A股 :沪市A股的代码是以600、601或603打头;★★★
3、沪市B股:沪市B股的代码是以900打头;
4、深市A股 :深市A股的代码是以000打头;★★★
5、中小板 :中小板的代码是002打头;
6、深圳B股: 深圳B股的代码是以200打头;
7、新股申购 :沪市新股申购的代码是以730打头 深市新股申购的代码与深市股票买卖代码一样;
8、配股代码:沪市以700打头,深市以080打头 权证,沪市是580打头 深市是031打头。
9、 400开头的股票是三板市场股票。
注意:国内上市公司可选择在上海证券交易所(上证)、深证证券交易所(深证)挂牌上市,中小型企业可选择北交所上市;
K线:
K线图(Candlestick
Charts)又称蜡烛图、日本线、【阴阳线】、棒线等,常用说法是“K线”,起源于日本十八世纪德川幕府时代(1603~1867年)的米市交易,用来计算米价每天的涨跌。
它是以每个交易日(或每个分析周期,甚至是月年)的开盘价、最高价、最低价、和收盘价绘制而成,结构上可分为上影线、下影线及中间实体三部分。
k线图:
示例:
二、项目架构
2.1今日指数技术选型
2.1.1 前端技术
名称 | 技术 | 场景 |
---|---|---|
基本股价 | vue-cli+vue+element+axios | |
报表 | echartsjs【百度,百度共享出去开源了】 | |
前端支持 | node webpack 等 |
2.1.2 后端技术栈
名称 | 技术 | 场景 |
---|---|---|
基础框架 | springboot、mybatis-springboot、springMVC | 项目基础骨架 |
安全框架 | boot-security+jwt | 认证与授权 |
缓存 | redis | 缓存 |
excel表格导出 | easyexcel 【国产阿里巴巴】 | |
小组件 | jode-date【日期】 、gson【json】 、guava 、httpClient | restTemplate 【模拟浏览器发送http请求】、线程池 | |
定时任务 | xxljob 【大众点评】 | |
文档框架 | swagger【生成接口文档】 | |
分库分表 | sharding-JDBC【apache】 | |
部署 | nginx |
2.1.3整体概览
2.2核心业务介绍
2.2.1业务结构预览
2.2.2 业务功能简介
1.定时任务调度服务,XXL-JOB通过RestTemplate+多线程动态拉去股票接口数据,刷入数据库;
2.国内指数服务;
3.板块指数服务;
4.涨幅榜展示功能;
5.涨停跌停数展示功能;
6.成交量对比展示功能;
7.个股涨停服务展示功能;
8.个股详情展示功能,包含分时行情、日k线、周K线图等;
9.个股描述服务;
10.报表导出服务.
三、软件开发流程说明
3.1软件开发流程
第1阶段: 需求分析
完成产品原型、需求规格说明书|| 需求说明书的编写。
产品原型:一般是通过网页(html)的形式展示业务功能,。比如包含页面的布局是什么样子的,点击某个菜单,打开什么页面,点击某个按钮,出现什么效果,都可以通过产品原型看到。
需求规格说明书, 一般来说就是使用 Word 文档来描述当前项目有哪些功能,每一项功能的需求及业务流程是什么样的,都会在文档中描述。
产品!
企业中给你原型:某个图片或者文字
第2阶段: 设计
设计的内容包含 产品设计、UI界面设计、概要设计、详细设计(接口设计是其中一个部分)、数据库设计。
在设计阶段,会出具相关的UI界面、及相关的设计文档。比如数据库设计,需要设计当前项目中涉及到哪些数据库,每一个数据库里面包含哪些表,这些表结构之间的关系是什么样的,表结构中包含哪些字段,字段类型都会在文档中描述清楚。
在该阶段查出:UI界面(纯静态的html页面)、概要设计文档(涵盖笼统的核心模块)、详细设计(具体功能的设计,包含接口设计产出:接口文档说明书)、数据库设计(设计业务关联的表、表与表之间的关系、表中的字段、字段的类型、索引等等)
第3阶段: 编码
项目管理人员或者项目组长|架构师任务分发;【日报,周报】
编写项目代码、并完成单元测试;
作为软件开发工程师,我们主要的工作就是在该阶段, 对分配给我们的模块功能,进行编码实现。编码实现完毕后,进行单元测试,单元测试通过后再进入到下一阶段;
第4阶段: 测试
在该阶段中主要由测试人员, 对部署在测试环境的项目进行功能测试, 并出具测试报告。(测试外包,外包提供测试报告,缺陷报告)
第5阶段: 上线运维
4个9999 保证全年99.9999%;
在项目上线之前, 会由运维人员准备服务器上的软件环境安装、配置, 配置完毕后, 再将我们开发好的项目,部署在服务器上运行。
沙箱环境 | 准生产环境:最大程度模拟生产环境,又不是生产环境;
注意:
我们作为软件开发工程师, 我们主要的任务是在编码阶段, 但是在一些小的项目组当中, 也会涉及到数据库的设计、测试等方面的工作。
3.2 软件开发角色分工
3.3 软件开发环境
在我们日常的软件开发中,会涉及到软件开发中的三套环境, 那么这三套环境分别是: 开发环境、测试环境、生产环境。
接下来,我们分别介绍一下这三套环境的作用和特点。
开发环境(development)
我们作为软件开发人员,在开发阶段使用的环境,就是开发环境,一般外部用户无法访问。
比如,我们在开发中使用的MySQL数据库和其他的一些常用软件,我们可以安装在本地, 也可以安装在一台专门的服务器中, 这些应用软件仅仅在软件开发过程中使用, 项目测试、上线时,我们不会使用这套环境了,这个环境就是开发环境。
测试环境(testing)
当软件开发工程师,将项目的功能模块开发完毕,并且单元测试通过后,就需要将项目部署到测试服务器上,让测试人员对项目进行测试。那这台测试服务器就是专门给测试人员使用的环境, 也就是测试环境,用于项目测试,一般外部用户无法访问。
生产环境(production)
当项目开发完毕,并且由测试人员测试通过之后,就可以上线项目,将项目部署到线上环境,并正式对外提供服务,这个线上环境也称之为生产环境。
拓展知识:
准生产环境: 对于有的公司来说,项目功能开发好, 并测试通过以后,并不是直接就上生产环境。为了保证我们开发的项目在上线之后能够完全满足要求,就需要把项目部署在真实的环境中, 测试一下是否完全符合要求啊,这时候就诞生了准生产环境,你可以把他当做生产环境的克隆体,准生产环境的服务器配置, 安装的应用软件(JDK、Tomcat、数据库、中间件 …) 的版本都一样,这种环境也称为 “仿真环境”。
ps:(postscript 补充)由于项目的性质和类型不同,有的项目可能不需要这个环境
四、后端开发环境搭建
开发工具版本要求:
4.1 数据库环境搭建
4.1.1 表结构介绍
4.1.2 数据导入
或者执行SQL脚本:
CREATE DATABASE `db_stock` CHARACTER SET 'utf8mb4' COLLATE 'utf8mb4_general_ci';
说明:
上述的表结构, 我们先简单的了解一下,大概有那些表, 每张表结构中存储什么样的数据, 有一个印象;
对于具体的表结构, 以及表结构中的字段, 在讲解具体的功能开发时, 我们再详细介绍;
4.2后端工程搭建
4.2.1 构建stock_parent父工程
构建stock_parent maven工程:
pom.xml(可以直接复制)
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.itheima.stock</groupId><artifactId>stock_parent</artifactId><version>1.0.0</version><properties><!--锁定项目字符集为UTF-8--><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><maven.compiler.encoding>UTF-8</maven.compiler.encoding><!--锁定Java版本为1.8--><maven.compiler.source>8</maven.compiler.source><maven.compiler.target>8</maven.compiler.target><maven.test.skip>true</maven.test.skip><spring-boot.version>2.7.4</spring-boot.version><mybatis-spring-boot-starter.version>2.2.2</mybatis-spring-boot-starter.version><pagehelper-spring-boot-starter.version>1.4.5</pagehelper-spring-boot-starter.version><druid-spring-boot-starter.version>1.2.12</druid-spring-boot-starter.version><sharding-jdbc-spring-boot-starter.version>4.0.0-RC1</sharding-jdbc-spring-boot-starter.version><mysql.version>8.0.30</mysql.version><fastjson.version>1.2.83</fastjson.version><joda-time.version>2.11.2</joda-time.version><springfox-swagger2.version>3.0.0</springfox-swagger2.version><jjwt.version>0.9.1</jjwt.version><xxl-job-core.version>2.3.1</xxl-job-core.version><easyexcel.version>3.1.1</easyexcel.version><druid.version>1.2.12</druid.version><guava.version>31.1-jre</guava.version><maven-surefire-plugin.version>2.22.2</maven-surefire-plugin.version></properties><dependencyManagement><dependencies><!--声明springboot 依赖--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-dependencies</artifactId><version>${spring-boot.version}</version><type>pom</type><scope>import</scope></dependency><!--声明mybatis 起步依赖--><dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>${mybatis-spring-boot-starter.version}</version></dependency><!--声明pageHelper 起步依赖--><dependency><groupId>com.github.pagehelper</groupId><artifactId>pagehelper-spring-boot-starter</artifactId><version>${pagehelper-spring-boot-starter.version}</version></dependency><!--声明druid 起步依赖--><dependency><groupId>com.alibaba</groupId><artifactId>druid-spring-boot-starter</artifactId><version>${druid-spring-boot-starter.version}</version></dependency><!--声明sharding jdbc 起步依赖--><dependency><groupId>org.apache.shardingsphere</groupId><artifactId>sharding-jdbc-spring-boot-starter</artifactId><version>${sharding-jdbc-spring-boot-starter.version}</version></dependency><!--声明mysql驱动依赖--><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>${mysql.version}</version></dependency><!--声明fastjson 依赖--><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>${fastjson.version}</version></dependency><!--声明druid 依赖--><dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>${druid.version}</version></dependency><!--声明 swagger依赖--><dependency><groupId>io.springfox</groupId><artifactId>springfox-swagger2</artifactId><version>${springfox-swagger2.version}</version></dependency><dependency><groupId>io.springfox</groupId><artifactId>springfox-swagger-ui</artifactId><version>${springfox-swagger2.version}</version></dependency><!--声明jwt依赖--><dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt</artifactId><version>${jjwt.version}</version></dependency><!--声明easyexcel依赖 --><dependency><groupId>com.alibaba</groupId><artifactId>easyexcel</artifactId><version>${easyexcel.version}</version></dependency><!--声明xxl-job依赖--><dependency><groupId>com.xuxueli</groupId><artifactId>xxl-job-core</artifactId><version>${xxl-job-core.version}</version></dependency><!--声明joda-time依赖--><dependency><groupId>joda-time</groupId><artifactId>joda-time</artifactId><version>${joda-time.version}</version></dependency><!--声明guava依赖--><dependency><groupId>com.google.guava</groupId><artifactId>guava</artifactId><version>${guava.version}</version></dependency><!--开发的时候,频繁重启项目测试,提升重启速度--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-devtools</artifactId><version>${spring-boot.version}</version></dependency></dependencies></dependencyManagement><build><pluginManagement><plugins><!--Springboot核心插件--><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><version>${spring-boot.version}</version><configuration><excludes><!--插件运行时排除依赖:这两个依赖都是在编译期间有作用,运行期间用,打包时候排除掉--><exclude><groupId>org.springframework.boot</groupId><artifactId>spring-boot-configuration-processor</artifactId></exclude><exclude><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></exclude></excludes></configuration></plugin><!--打包跳过test --><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-surefire-plugin</artifactId><version>${maven-surefire-plugin.version}</version><configuration><skip>${maven.test.skip}</skip></configuration></plugin></plugins></pluginManagement></build></project>
注意事项:
1.通过dependencyManagement、pluginManagement锁定开发中的依赖和插件的版本;
2.复制pom文件中内容到你的工程中可能会报错,不要紧张,是因为你的仓库中没有对应的依赖。继续往后学习
4.2.2 构建stock_backendj基础工程
创建stock_paren的maven子工程stock_backend
stock_backend工程创建完成以后,stock_parent工程中pom文件变化:
4.2.3 引入依赖
stock_backend工程被stock_parent父工程,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 http://maven.apache.org/xsd/maven-4.0.0.xsd"><!--继承父工程stock_parent--><parent><artifactId>stock_parent</artifactId><groupId>com.itheima.stock</groupId><version>1.0.0</version></parent><modelVersion>4.0.0</modelVersion><artifactId>stock_backend</artifactId><dependencies><!-- web 起步依赖:提供web开发基本功能 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!--aop 起步依赖:提供aop开发基本功能--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId></dependency><!--test 起步依赖:提供测试相关功能--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><!--mybatis起步依赖:提供mybatis功能--><dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId></dependency><!--pagehelper 起步依赖:基于分页插件为mybatis提供分页功能--><dependency><groupId>com.github.pagehelper</groupId><artifactId>pagehelper-spring-boot-starter</artifactId></dependency><!--druid 起步依赖:提供连接数据库数据源功能--><dependency><groupId>com.alibaba</groupId><artifactId>druid-spring-boot-starter</artifactId></dependency><!--mysql 依赖:提供连接MySQL数据库功能--><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><scope>runtime</scope></dependency><!--配置提示依赖--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-configuration-processor</artifactId><optional>true</optional></dependency><!--时间小工具joda依赖--><dependency><groupId>joda-time</groupId><artifactId>joda-time</artifactId></dependency><!--lombok依赖:提供简化pojo类编写的功能比如生成get和set方法--><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><scope>provided</scope><optional>true</optional></dependency><!--springboot 开发工具依赖--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-devtools</artifactId><scope>runtime</scope><optional>true</optional></dependency></dependencies><build><!--打包名称--><finalName>${project.artifactId}</finalName><plugins><!--打成可执行jar包插件--><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin><!-- 打包跳过test --><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-surefire-plugin</artifactId></plugin></plugins></build></project>
4.2.4 配置yml
在src/main/resources 创建application.yml
# web定义
server:port: 8081spring:# 配置mysql数据源datasource:druid:username: rootpassword: rooturl: jdbc:mysql://127.0.0.1:3306/db_stock?useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true&useSSL=false&serverTimezone=Asia/Shanghaidriver-class-name: com.mysql.cj.jdbc.Driver# 初始化时建立物理连接的个数。初始化发生在显示调用 init 方法,或者第一次 getConnection 时initialSize: 6# 最小连接池数量minIdle: 2# 最大连接池数量maxActive: 20# 获取连接时最大等待时间,单位毫秒。配置了 maxWait 之后,缺省启用公平锁,# 并发效率会有所下降,如果需要可以通过配置 useUnfairLock 属性为 true 使用非公平锁。maxWait: 60000# 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒timeBetweenEvictionRunsMillis: 60000# 配置一个连接在池中最小生存的时间,单位是毫秒minEvictableIdleTimeMillis: 300000# 用来检测连接是否有效的 sql 因数据库方言而差, 例如 oracle 应该写成 SELECT 1 FROM DUALvalidationQuery: SELECT 1 FROM DUAL# 建议配置为 true,不影响性能,并且保证安全性。申请连接的时候检测,# 如果空闲时间大于 timeBetweenEvictionRunsMillis,执行 validationQuery 检测连接是否有效。testWhileIdle: true# 申请连接时执行 validationQuery 检测连接是否有效,做了这个配置会降低性能。testOnBorrow: false# 归还连接时执行 validationQuery 检测连接是否有效,做了这个配置会降低性能。testOnReturn: false# 是否自动回收超时连接poolPreparedStatements: truemaxPoolPreparedStatementPerConnectionSize: 20# 配置监控统计拦截的filters,去掉后监控界面sql无法统计,'wall'用于防火墙filters: stat,wall# 通过connectProperties属性来打开mergeSql功能;慢SQL记录connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000# 配置mybatis
mybatis:type-aliases-package: com.itheima.stock.pojomapper-locations: classpath:mapper/*.xmlconfiguration:map-underscore-to-camel-case: truecache-enabled: false #使全局的映射器启用或禁用缓存。lazy-loading-enabled: false #全局启用或禁用延迟加载。当禁用时,所有关联对象都会即时加载。aggressive-lazy-loading: true #当启用时,有延迟加载属性的对象在被调用时将会完全加载任意属性。否则,每种属性将会按需要加载。# pagehelper配置
pagehelper:helper-dialect: mysql #指定分页数据库类型(方言)reasonable: true #合理查询超过最大也,则查询最后一页support-methods-arguments: true # 支持通过Mapper接口参数来传递分页参数,默认falseparams: pacount=countSql # POJO或者Map中发现了countSql属性,就会作为count参数使用returnPageInfo: check # always总是返回PageInfo类型,check检查返回类型是否为PageInfo,none返回Page
4.2.5 定义main启动类
package com.itheima.stock;import lombok.extern.slf4j.Slf4j;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;/*** @author ghy* @version 1.0* @description 引导类* @date 2022/10/1 19:47:04*/
@Slf4j
@SpringBootApplication
@MapperScan(basePackages = {"com.itheima.stock.mapper"})
public class StockApp {public static void main(String[] args) {SpringApplication.run(StockApp.class,args);log.info("项目启动成功......");}
}
4.2.6 定义web测试接口
package com.itheima.stock.controller;import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;/*** @author ghy* @version 1.0* @description 用户表现层* @date 2022/10/1 19:50:29*/
@RestController
@RequestMapping(path = "/api")
public class UserController {@GetMapping(path = "/test")public String getName() {return "itheima";}
}
4.2.7 测试环境搭建
到这儿,工程基础环境就搭建完毕了
4.3 快速构建mybatis业务开发环境
4.3.1 mybatis逆向工程使用
借助mybatisX工具生成基础代码
第一步:通过idea自带的database组件连接数据库:
第二步:配置pojo实体类选项
第三步:配置mapper接口和xml选项:
4.3.2 集成mybatis的工程结构
4.3.3 环境整体测试
目的:我们通过一个简单的web接口访问数据库,验证工程搭建情况
接口功能说明:查询所有上市公司主营业务数据(阅读理解能力!)
思考:
(查询(select)表(stock_business))
技术mybatis
mapper接口
mapper映射
实体类
接口url:/api/quot/stock/business/all
思考:
web层controller 方法 :参数 返回值(集合)
定义mapper接口方法
StockBusinessMapper接口和xml定义查询所有股票业务信息的接口方法:
/*** 查询所有股票主营业务数据** @return*/List<StockBusiness> selectAllStockBusiness();
<!--1.查询所有股票主营业务数据--><select id="selectAllStockBusiness" resultMap="BaseResultMap"> select <include refid="Base_Column_List"/> from stock_business </select>
定义服务接口及实现
package com.itheima.stock.service;import com.itheima.stock.pojo.StockBusiness;import java.util.List;/*** @author ghy* @version 1.0* @description 股票服务接口* @date 2022/10/1 21:05:44*/
public interface StockService {/*** 获取所有股票主营业务数据** @return*/List<StockBusiness> getAllStockBusiness();
}
定义服务接口实现
package com.itheima.stock.service.impl;import com.itheima.stock.common.domain.InnerMarketDomain;
import com.itheima.stock.common.domain.StockInfoConfig;
import com.itheima.stock.mapper.StockBusinessMapper;
import com.itheima.stock.mapper.StockMarketIndexInfoMapper;
import com.itheima.stock.pojo.StockBusiness;
import com.itheima.stock.service.StockService;
import com.itheima.stock.vo.resp.R;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;import java.util.List;/*** @author ghy* @version 1.0* @description 股票服务接口实现类* @date 2022/10/1 21:09:30*/
@Service
public class StockServiceImpl implements StockService {@Autowiredprivate StockBusinessMapper stockBusinessMapper;@Overridepublic List<StockBusiness> getAllStockBusiness() {return stockBusinessMapper.selectAllStockBusiness();}
}
定义web访问接口
package com.itheima.stock.controller;import com.itheima.stock.pojo.StockBusiness;
import com.itheima.stock.service.StockService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import java.util.List;/*** @author ghy* @version 1.0* @description 股票访问层* @date 2022/10/1 21:17:30*/
@RestController
@RequestMapping(path = "/api/quot")
@CrossOrigin
public class StockController {@Autowiredprivate StockService stockService;@GetMapping(path = "/stock/business/all")public List<StockBusiness> getAllBusiness() {return stockService.getAllStockBusiness();}}
启动项目测试
五、前端开发环境搭建
5.1前端环境准备
5.1.1 node安装
安装完成在cmd中会返回如下内容:
(前端的代码过于复杂,我已经上传了代码文件到资料)
六、登录功能实现
6.1 需求分析
6.1.1 页面原型效果
6.1.2 相关的表结构
sys_user表如下:
6.1.3 访问接口定义
请求接口:/api/login
请求方式:POST
请求数据示例:
{
username:‘zhangsan’,//用户名
password:‘666’,//密码
code:‘1234’ //校验码
}
响应数据:
{
“code”: 1,//成功1 失败0
“data”: {
“id”:“1237365636208922624”,
“username”:“zhangsan”,
“nickName”:“xiaozhang”,
“phone”:“1886702304”
}
}
6.1.4封装请求和响应VO
请求VO封装
package com.itheima.stock.vo.req;import lombok.Data;/*** 登录请求Vo ,这个对象封装的就是登录接口的请求数据*/
@Data
public class LoginReqVo {/*** 用户名*/private String username;/*** 密码*/private String password;/*** 验证码*/private String code;
}
响应VO
package com.itheima.stock.vo.resp;import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;/*** 登录接口响应Vo*/
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class LoginRespVo {/*** 用户ID*/private String id;/*** 电话*/private String phone;/*** 用户名*/private String username;/*** 昵称*/private String nickName;}
定义公共响应VO
package com.itheima.stock.vo.resp;import com.fasterxml.jackson.annotation.JsonInclude;import java.io.Serializable;/*** @author ghy* @version 1.0* @description 统一响应数据格式类* @date 2022/10/1 22:38:39*/
@JsonInclude(JsonInclude.Include.NON_NULL)
public class R<T> implements Serializable {private static final long serialVersionUID = 7735505903525411467L;// 成功值private static final int SUCCESS_CODE = 1;// 失败值private static final int ERROR_CODE = 0;//状态码private int code;//消息private String msg;//返回数据private T data;private R(int code){this.code = code;}private R(int code, T data){this.code = code;this.data = data;}private R(int code, String msg){this.code = code;this.msg = msg;}private R(int code, String msg, T data){this.code = code;this.msg = msg;this.data = data;}public static <T> R<T> ok(){return new R<T>(SUCCESS_CODE,"success");}public static <T> R<T> ok(String msg){return new R<T>(SUCCESS_CODE,msg);}public static <T> R<T> ok(T data){return new R<T>(SUCCESS_CODE,data);}public static <T> R<T> ok(String msg, T data){return new R<T>(SUCCESS_CODE,msg,data);}public static <T> R<T> error(){return new R<T>(ERROR_CODE,"error");}public static <T> R<T> error(String msg){return new R<T>(ERROR_CODE,msg);}public static <T> R<T> error(int code, String msg){return new R<T>(code,msg);}public int getCode(){return code;}public String getMsg(){return msg;}public T getData(){return data;}
}
定义响应状态枚举
package com.itheima.stock.common.enums;/*** @author ghy* @version 1.0* @description 响应状态枚举类* @date 2022/10/1 22:42:28*/
public enum ResponseCode {ERROR(0, "操作失败"),SUCCESS(1, "操作成功"),DATA_ERROR(0, "参数异常"),NO_RESPONSE_DATA(0, "无响应数据"),SYSTEM_VERIFY_CODE_NOT_EMPTY(0, "验证码不能为空"),SYSTEM_VERIFY_CODE_ERROR(0, "验证码错误"),SYSTEM_USERNAME_NOT_EMPTY(0, "账号不能为空"),SYSTEM_USERNAME_NOT_EXISTS(0, "账号不存在"),SYSTEM_USERNAME_EXPIRED(0, "账户过期"),SYSTEM_USERNAME_LOCKED(0, "账户被锁"),SYSTEM_USERNAME_DISABLED(0, "账户被禁用"),SYSTEM_PASSWORD_ERROR(0, "账号或密码错误"),SYSTEM_PASSWORD_EXPIRED(0, "密码过期"),SYSTEM_USERNAME_OFFLINE(0, "已下线,请重新登录"),SYSTEM_ERROR(0, "系统异常请稍后再试"),ACCOUNT_EXISTS_ERROR(0, "该账号已存在"),TOKEN_ERROR(2, "用户未登录,请先登录"),NOT_PERMISSION(3, "没有权限访问该资源"),TOKEN_NOT_NULL(-1, "token 不能为空"),TOKEN_NO_AVAIL(-1, "token无效或过期"),TOKEN_PAST_DUE(-1, "登录失效,请重新登录"),TOKEN_EXISTS(-1, "账号异地登录,你已被迫退出"),OPERATION_MENU_PERMISSION_CATALOG_ERROR(0, "操作后的菜单类型是目录,所属菜单必须为默认顶级菜单或者目录"),OPERATION_MENU_PERMISSION_MENU_ERROR(0, "操作后的菜单类型是菜单,所属菜单必须为目录类型"),OPERATION_MENU_PERMISSION_BTN_ERROR(0, "操作后的菜单类型是按钮,所属菜单必须为菜单类型"),OPERATION_MENU_PERMISSION_URL_NOT_NULL(0, "菜单权限的url不能为空"),OPERATION_MENU_PERMISSION_URL_PERMS_NULL(0, "菜单权限的标识符不能为空"),OPERATION_MENU_PERMISSION_URL_METHOD_NULL(0, "菜单权限的请求方式不能为空"),OPERATION_MENU_PERMISSION_URL_CODE_NULL(0, "菜单权限的按钮标识不能为空"),OPERATION_MENU_PERMISSION_UPDATE(0, "操作的菜单权限存在子集关联不允许变更"),ROLE_PERMISSION_RELATION(0, "该菜单权限存在子集关联,不允许删除"),OLD_PASSWORD_ERROR(0, "旧密码不匹配");/*** 状态码*/private int code;/*** 消息*/private String message;private ResponseCode(int code, String message) {this.code = code;this.message = message;}public int getCode() {return this.code;}public String getMessage() {return this.message;}
}
6.2 登录功能开发实现
6.2.1 stock_backend导入依赖资源
<!--apache工具包:java.lang 包中类的工具类,String -->
<dependency><groupId>org.apache.commons</groupId><artifactId>commons-lang3</artifactId>
</dependency>
<!--密码加密和校验工具包:安全相关功能,比如密码加密器-->
<dependency><groupId>org.springframework.security</groupId><artifactId>spring-security-crypto</artifactId>
</dependency>
<!--guava工具包 Java开发过程工具类,比如项目中使用的Strings-->
<dependency><groupId>com.google.guava</groupId><artifactId>guava</artifactId>
</dependency>
6.2.2 配置密码加密服务
package com.itheima.stock.config;import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;/*** @author ghy* @version 1.0* @description 公共配置类* @date 2022/10/1 21:54:41*/
@Configuration
public class CommonConfig {/*** 密码加密器 BCryptPasswordEncoder 采用 SHA-256 算法* @return*/@Beanpublic PasswordEncoder passwordEncoder(){BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();return bCryptPasswordEncoder;}}
密码加密测试:
创建测试基类:在src/test拆功能键Base Test.java
package com.itheima.stock;import org.springframework.boot.test.context.SpringBootTest;/*** @author ghy* @version 1.0* @description 单元测试基类* @date 2022/10/1 19:59:12*/
@SpringBootTest
public class BaseTest {}
创建测试类:
package com.itheima.stock.config;import com.itheima.stock.BaseTest;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.password.PasswordEncoder;/*** @author ghy* @version 1.0* @description* @date 2022/10/1 22:08:19*/
public class CommonConfigTest extends BaseTest {@Autowiredprivate PasswordEncoder passwordEncoder;/*** 测试 密码加密/比对*/@Testpublic void testEncodePassword() {// 模拟未加密的密码String rawPassword = "123456";// 对密码加密得到加密后的密码:$2a$10$PWfx6UNdiUMEnqr.Y0UiP.NUFOTjQmG6wU9SSlbY5lXGBIB1C9XwS// 注意:统一个密码使用encode方法多次加密的密文是并不一样String encodePassword = passwordEncoder.encode(rawPassword);// 输出加密后的密码System.out.println(encodePassword);// 使用未加密的密码和加密后的密码比对,比对成功返回true,否则返回falseboolean matches = passwordEncoder.matches(rawPassword, encodePassword);System.out.println(matches);}
}
6.2.3 登录接口方法定义
package com.itheima.stock.controller;import com.itheima.stock.service.UserService;
import com.itheima.stock.vo.req.LoginReqVo;
import com.itheima.stock.vo.resp.LoginRespVo;
import com.itheima.stock.vo.resp.R;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;/*** @author by itheima* @Date 2021/12/29* @Description 定义用户访问层*/
@RestController
@RequestMapping("/api")
@CrossOrigin
public class UserController {@Autowiredprivate UserService userService;/*** 用户登录功能实现* @param vo* @return*/@PostMapping("/login")public R<LoginRespVo> login(@RequestBody LoginReqVo vo){R<LoginRespVo> r= this.userService.login(vo);return r;}// @GetMapping("/test")
// public String getName(){
// return "itheima";
// }
}
6.2.4 定义登录服务接口和实现
服务接口:
package com.itheima.stock.service;import com.itheima.stock.vo.req.LoginReqVo;
import com.itheima.stock.vo.resp.LoginRespVo;
import com.itheima.stock.vo.resp.R;/*** @author by itheima* @Date 2021/12/30* @Description 用户服务*/
public interface UserService {/*** 用户登录功能实现* @param vo* @return*/R<LoginRespVo> login(LoginReqVo vo);
}
服务接口实现:
package com.itheima.stock.service.impl;import com.google.common.base.Strings;
import com.itheima.stock.common.enums.ResponseCode;
import com.itheima.stock.mapper.SysUserMapper;
import com.itheima.stock.pojo.SysUser;
import com.itheima.stock.service.UserService;
import com.itheima.stock.vo.req.LoginReqVo;
import com.itheima.stock.vo.resp.LoginRespVo;
import com.itheima.stock.vo.resp.R;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;/*** @author by itheima* @Date 2021/12/30* @Description 定义服务接口实现*/
@Service("userService")
public class UserServiceImpl implements UserService {@Autowiredprivate SysUserMapper sysUserMapper;@Autowiredprivate PasswordEncoder passwordEncoder;@Overridepublic R<LoginRespVo> login(LoginReqVo vo) {if (vo==null || Strings.isNullOrEmpty(vo.getUsername()) || Strings.isNullOrEmpty(vo.getPassword())){return R.error(ResponseCode.DATA_ERROR.getMessage());}//根据用户名查询用户信息SysUser user=this.sysUserMapper.findByUserName(vo.getUsername());//判断用户是否存在,存在则密码校验比对if (user==null || !passwordEncoder.matches(vo.getPassword(),user.getPassword())){return R.error(ResponseCode.SYSTEM_PASSWORD_ERROR.getMessage());}//组装登录成功数据LoginRespVo respVo = new LoginRespVo();//属性名称与类型必须相同,否则copy不到BeanUtils.copyProperties(user,respVo);return R.ok(respVo);}
}
6.2.5 定义mapper方法
在SysUserMapper下定义接口方法:
/*** 根据用户名查询用户信息* @param username* @return*/SysUser findByUserName(@Param("username") String username);
绑定xml:
<select id="findByUserName" resultMap="BaseResultMap">select <include refid="Base_Column_List"/> from sys_user whereusername=#{username}</select>