目录
一、SpringBoot快速上手
1、SpringBoot介绍
2、SpringBoot特点
3、快速创建SpringBoot应用
4、SpringBoot开发热部署
二、Web开发基础
1、Web入门
2、控制器
3、路由映射
4、参数传递
三、Web开发进阶
1、静态资源访问
2、文件上传原理
3、拦截器
四、构建RESTful服务
1、RESTful介绍
2、RESTful特点
3、RESTful API
4、HTTP状态码
5、SpringBoot实现RESTful API
6、Swagger
使用Swagger生成Web API文档
配置Swagger
使用Swagger2进行接口测试
Swagger常用注解
五、MybatisPlus快速上手
1、ORM介绍
2、MyBatis-Plus介绍
添加依赖
全局配置
Mybatis CRUD 注解
Mybatis CRUD 操作
Mybatis-Plus 注解
Mybatis-Plus CRUD操作
六、多表查询及分页查询
多表查询
多表查询操作
条件查询
分页查询
七、Vue框架快速上手
1、前端环境准备
2、Vue框架介绍
MVVM模式:
Vue快速入门:
八、Vue组件化开发
1、NPM简介
2、NodeJS安装
3、NPM使用
4、Vue Cli使用
5、组件化开发
6、组件的构成
九、第三方组件 Element-UI
1、组件间的传值
2、Element-UI介绍
3、第三方图标库
十、Axios网络请求
1、Axios简介
2、发送网络请求
发送GET请求
发生POST请求
异步回调问题(async/await)
其他请求方式
与Vue整合
3、Axios使用
为什么会出现跨域问题
跨域问题解决方法
十一、前端路由VueRouter
1、VueRouter安装与使用
VueRouter安装:
创建路由组件
声明路由连接和占位标签
创建路由模块
挂载路由模块
实现效果
2、VueRouter进阶
路由重定向
嵌套路由
动态路由
编程式导航
导航守卫
十二、状态管理VueX
1、VueX介绍
2、状态管理
最简单的store
State
对象展开运算符
Getter
Mutation
Action
Module
总结
十三、前端数据模拟Mock.js
1、Mock.js介绍
2、基本使用
3、核心方法
4、数据生成规则
十四、企业级后台集成方案
1、vue-element-admin介绍
十五、跨域认证
1、Session认证
2、Token认证
3、JWT
4、JWT组成
Header
Payload
Signature
5、JWT的特点
6、JWT的实现
十七、Springboot+Vue云端环境配置
1、安装MySQL
2、安装Nginx
3、配置JDK
十八、Springboot+Vue项目部署
1、部署Vue项目
2、打包运行Java程序
@RestController
public class IndexController {
@GetMapping("/index")
public String index(){
return "欢迎访问首页";
}
}
org.springframework.boot
spring-boot-devtools
true
spring:
devtools:
restart:
enabled: true #热部署生效
additional-paths: src/main/java #设置重启目录
exclude: static/** #设置classpath目录下的WEB-INF文件夹内容修改不重启
org.springframework.boot
spring-boot-starter-web
@Controller
public class IndexController {
@GetMapping("/index")
public String index(ModelMap map){
map.addAttribute("name","张三");
return "index";
}
}
@RestController
public class IndexController {
@GetMapping("/user")
public User getUser(){
User user = new User();
user.setUsername("张三");
user.setPassword("123");
return user;
}
}
@RestController
public class IndexController {
// http://localhost:8888/index?nickname=zhangsan
@GetMapping("/index")
public String index(@RequestParam("nickname") String name){
return "你好"+name;
}
}
@RestController
public class IndexController {
// http://localhost:8888/index?nickname=zhangsan
@GetMapping("/index")
public String index(String nickname){
return "你好"+nickname;
}
}
@RestController
public class IndexController {
// http://localhost:8888/index?nickname=zhangsan&phone=123
@GetMapping("/index")
public String index(String name,String phone){
return "你好"+name+phone;
}
}
@GetMapping("/getUser/{id}")
public String getUser(@PathVariable String id){
System.out.println("id->"+id);
return "getUser";
}
spring:
mvc:
static-path-pattern: /static/**
web:
resources:
static-locations: classpath:/static/ #静态资源
SpringBoot实现文件上传功能
Springboot工程嵌入的tomcat限制了请求的文件大小,每个文件的配置最大为1MB,单次请求的文件的总数不能大于10MB。
要更改这个默认值需要在配置文件application.yml中加入两个配置:
spring:
servlet:
multipart:
max-file-size: 10GB #文化最大10G
max-request-size: 10GB #单次请求文件总数不能超过10G
当表单的enctype="multipart/form-data"时,可以使用MultipartFile获取上传的文件数据,再通过transferTo方法将其写入磁盘中:
@RestController
public class FileController {
/**
* 默认定位到的当前用户目录("user.dir")(即工程根目录)
* JVM就可以据"user.dir" + "你自己设置的目录" 得到完整的路径(即绝对路径)
*/
// private static final String UPLOADED_FOLDER = System.getProperty("user.dir")+"/upload/";
@PostMapping("/upload")
public String upload(MultipartFile file, HttpServletRequest request)throws Exception{
System.out.println("文件大小:"+file.getSize());
System.out.println("文件的ContentType:"+file.getContentType());
System.out.println("文件的初始名字:"+file.getOriginalFilename());
String path = request.getServletContext().getRealPath("/upload/");
System.out.println("获取web服务器的运行目录:"+path);
saveFile(file,path);
return "upload success";
}
public void saveFile(MultipartFile f,String path)throws IOException{
File upDir = new File(path);
if (!upDir.exists()){
upDir.mkdir();
}
File file = new File(path+f.getOriginalFilename());
f.transferTo(file);
}
}
public class LoginInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("LoginInterceptor");
return true;
}
}
@Configuration // Configuration必须要添加
public class WebConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LoginInterceptor());
// registry.addInterceptor(new LoginInterceptor()).addPathPatterns("/user/**"); // 拦截所有user下面的接口
}
}
RESTful是目前流行的互联网软件服务架构设计风格。
REST(Representational State Transfer,表述性状态转移) 一词是由Roy Thomas Fielding在2000年的博士论文中提出的,它定义了互联网软件服务的架构原则,如果一个架构符合REST原则,则称之为RESTful架构。
REST并不是一个标准,它更像一组客户端和服务端交互时的架构理念和设计原则,基于这种架构理念和设计原则的Web API更加简洁、更有层次。
HTTP Method | 接口地址 | 接口描述 |
---|---|---|
POST | /user | 创建用户 |
GET | /user/id | 根据id获取用户信息 |
PUT | /user | 更新用户 |
DELETE | /user/id | 根据id删除对应用户 |
@RestController
public class UserController {
// @PathVariable:注:路由内属性与形参相同可简写,
// 若不相同,则需要加上对应的名称绑定,如:@PathVariable("id")
@GetMapping("/user/{id}")
public String getUserById(@PathVariable int id){
System.out.println(id);
return "根据ID获取用户信息";
}
@PostMapping("/user")
public String save(User user){
return "添加用户";
}
@PutMapping("/user")
public String update(User user){
return "更新用户";
}
@DeleteMapping("/user/{id}")
public String deleteById(@PathVariable int id){
System.out.println(id);
return "根据id删除用户";
}
}
io.springfox
springfox-swagger2
2.9.2
io.springfox
springfox-swagger-ui
2.9.2
@Configuration // 告诉spring容器,这个类是一个配置类
@EnableSwagger2 // 启用Swagger2功能
public class Swagger2Config {
@Bean
public Docket createRestApi(){
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
.select()
// com包下的所有API都交给Swagger2管理
.apis(RequestHandlerSelectors.basePackage("com"))
.paths(PathSelectors.any())
.build();
}
// API文档页面显示信息
private ApiInfo apiInfo(){
return new ApiInfoBuilder()
.title("文件系统项目API") // 标题
.description("学习Springboot+Vue项目") // 描述
.build();
}
}
com.baomidou
mybatis-plus-boot-starter
3.5.2
mysql
mysql-connector-java
com.alibaba
druid-spring-boot-starter
1.2.13-SNSAPSHOT
@Mapper
public interface UserMapper {
// 增加用户
@Insert("insert into user(username,password,birthday) values (#{username},#{password},#{birthday})")
int add(User user);
// 根据id删除用户
@Delete("delete from user where id=#{id}")
int delete(int id);
// 更新用户信息
@Update("update user set username=#{username},password=#{password},birthday=#{birthday} where id=#{id}")
int update(User user);
// 根据id查询用户
@Select("select * from user where id=#{id}")
User findById(int id);
// 查询所有用户
@Select("select * from user")
List findAll();
}
@TableName("t_user")
public class User {
@TableId(type = IdType.AUTO)
private int id;
private String username;
private String password;
private String birthday;
// 描述用户的所有订单
@TableField(exist = false) // 表示在数据库表中不存在,不需要做映射
private List orders;
public User() {
}
public User(String username, String password, String birthday) {
this.username = username;
this.password = password;
this.birthday = birthday;
}
....省略了getter和setter方法
@Override
public String toString() {
return "User{" +
"id=" + id +
", username='" + username + '\'' +
", password='" + password + '\'' +
", birthday='" + birthday + '\'' +
'}';
}
}
@TableName("t_order")
public class Order {
private int id;
@TableField("order_time")
private String orderTime;
private double total;
@TableField(exist = false)
private User user;
public Order() {
}
public Order(String orderTime, double total, User user) {
this.orderTime = orderTime;
this.total = total;
this.user = user;
}
....省略了getter和setter方法
@Override
public String toString() {
return "Order{" +
"id=" + id +
", orderTime='" + orderTime + '\'' +
", total=" + total +
", user=" + user +
'}';
}
}
@Mapper
public interface UserMapper extends BaseMapper {
// 根据id查用户
@Select("select * from t_user where id=#{id}")
User selectById(int id);
// 查询用户及其所有的订单
@Select("select * from t_user")
@Results(
{
@Result(column = "id",property = "id"), // column:字段,property:映射到实体类的属性
@Result(column = "username",property = "username"),
@Result(column = "password",property = "password"),
@Result(column = "birthday",property = "birthday"),
@Result(column = "id",property = "orders",javaType = List.class,
many = @Many(select = "com.org.mapper.OrderMapper.selectByUid")
// 通过user的id去orderMapper的selectByUid查询所以该用户的订单
)
}
)
List selectAllUserAndOrders();
}
@Mapper
public interface OrderMapper extends BaseMapper {
@Select("select * from t_order where uid=#{uid}")
List selectByUid(int uid);
// 查询所有的订单,同时查询订单用户
@Select("select * from t_order")
@Results({
@Result(column = "id",property = "id"),
@Result(column = "order_time",property = "orderTime"),
@Result(column = "total",property = "total"),
@Result(column = "uid",property = "user",javaType = User.class,
one=@One(select = "com.org.mapper.UserMapper.selectById")
// 根据order的uid到UserMapper的selectById方法中查询该订单所属的用户
),
})
List selectAllOrderAndUser();
}
@RestController
public class UserController {
@Autowired
private UserMapper userMapper;
@GetMapping("/user")
public List query() {
// 查询用户及其所有订单
List userList = userMapper.selectAllUserAndOrders();
return userList;
}
}
@RestController
public class OrderController {
@Autowired
private OrderMapper orderMapper;
// 查询订单及其所属的用户
@GetMapping("/order/findAll")
public List findAll(){
List orderList = orderMapper.selectAllOrderAndUser();
return orderList;
}
}
@GetMapping("/user")
public List query() {
// 条件查询
QueryWrapper queryWrapper = new QueryWrapper<>(); // 创建实例
queryWrapper.eq("username","tom"); // 查询username为tom的用户
List userList = userMapper.selectList(queryWrapper); // 将条件作为参数传入查询方法,若无条件,则在方法传入null
return userList;
}
条件 | 条件实现功能 | 例子 |
---|---|---|
eq | 等于 = | 例: eq("name", "老王")--->name = '老王' |
ne | 不等于 <> | 例: ne("name", "老王")--->name <> '老王' |
gt | 大于 > | 例: gt("age", 18)--->age > 18 |
ge | 大于等于 >= | 例: ge("age", 18)--->age >= 18 |
lt | 小于 < | 例: lt("age", 18)--->age < 18 |
le | 小于等于 <= | 例: le("age", 18)--->age <= 18 |
between | BETWEEN 值1 AND 值2 | 例: between("age", 18, 30)--->age between 18 and 30 |
notBetween | NOT BETWEEN 值1 AND 值2 | 例: notBetween("age", 18, 30)--->age not between 18 and 30 |
like | LIKE '%值%' | 例: like("name", "王")--->name like '%王%' |
notLike | NOT LIKE '%值%' | 例: notLike("name", "王")--->name not like '%王%' |
likeLeft | LIKE '%值' | 例: likeLeft("name", "王")--->name like '%王' |
likeRight | LIKE '值%' | 例: likeRight("name", "王")--->name like '王%' |
isNull | 字段 IS NULL | 例: isNull("name")--->name is null |
isNotNull | 字段 IS NOT NULL | 例: isNotNull("name")--->name is not null |
in | 字段 IN (v0, v1, ...) | 例: in("age", 1, 2, 3)--->age in (1,2,3) |
notIn | 字段 NOT IN (value.get(0), value.get(1), ...) | 例: notIn("age",{1,2,3})--->age not in (1,2,3) |
@Configuration
public class MybatisPlusConfig {
@Bean
public MybatisPlusInterceptor paginationInterceptor(){
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
PaginationInnerInterceptor paginationInnerInterceptor = new PaginationInnerInterceptor(DbType.MYSQL); // 数据库类型
interceptor.addInnerInterceptor(paginationInnerInterceptor);
return interceptor;
}
}
// 分页查询
@GetMapping("/user/findByPage")
public IPage findByPage(){
// 设置起始值及每页条数
Page page = new Page<>(0,2);
IPage iPage = userMapper.selectPage(page,null); // 第一个参数是page,第二个参数是查询条件
return iPage;
}
{{ message }}
const vm = {
// 指定数据源:即MVVM中的Model
data: function(){
return{
message: 'Hello Vue!'
}
}
}
const app = Vue.createApp(hello)
app.mount('#app) // 指定当前vue实例要控制页面的哪个区域
npm install -g @vue/cli
更多语法可在Vue官网学习!!
import Vue from 'vue'
import App from './App.vue'
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
Vue.use(ElementUI); // 全局注册
Vue.config.productionTip = false
new Vue({
render: h => h(App),
}).$mount('#app')
npm install font-awesome
npm install axios
import axios from 'axios';
// 向给定id的用户发起请求
axios.get('http://localhost:8080/user?id=123')
.then(function(response){
// 处理成功情况
console.log(response);
})
.catch(function(error){
// 处理失败情况
console.log(error);
})
.then(function(){
// 总是会执行
});
// 上述请求也可以按以下方式完成
axios.get('http://localhost:8080/user',{
params:{
id:123
}
})
.then(function(response){
// 处理成功情况
console.log(response);
})
.catch(function(error){
// 处理失败情况
console.log(error);
})
.then(function(){
// 总是会执行
});
axios.post('http://localhost:8080/user',{
firstName: 'Fred',
lastName: 'Flintstone'
})
.then(function(response){
console.log(response);
})
.catch(function(error){
console.log(error);
});
// 支持async/await 用法
async function getUser(){
try{
// 不需要.then就可以之间拿到response响应数据
const response = await.axios.get('http://localhost:8080/user?id=1');
console.log(response);
}catch(error){
console.error(error);
}
}
在实际项目开发中,几乎每个组件中都会用到axios发起的数据请求。此时会遇到如下两个问题:
每个组件中都需要导入axios
每次发送请求都需要填写完整的请求路径
可以通过全局配置的方法解决上述问题:
// 在main.js中导入axios,然后再继续配置
import axios from 'axios'
// 配置请求根路径
axios.defaults.baseURL = 'http://xxx'
// 将axios作为全局的自定义属性,每个组件可以在内部直接访问(Vue3)
app.config.globalProerties.$http = axios
// 将axios作为全局的自定义属性(不一定$http,可以自定义),每个组件可以在内部直接访问(Vue2)
Vue.prototype.$http = axios
//例如:直接在其他组件中写:this.$http.get()就可以实现axios的功能
Vue项目的网络请求一般在created里面做,这样页面一创建就会发送网络请求。
created:function(){
axios.get("http://localhost:8888/user")
.then((response)=>{ // 箭头函数:ES6语法,它的作用:它的作用域继承于父级(也就是Vue实例),如果用function(response),作用域就不是Vue实例
console.log(response.data);
this.tableData = response.data;
console.log(this.tableData);
})
.catch(function(error){
console.log(error);
})
},
当我们运行项目后,控制台显示报错了,这个的意思是没有明确授权同源策略,导致被CORS策略阻止。
为了保证浏览器的安全,不同源的客户端本在没有明确授权的情况下,不能读写对方资源,称为同源策略,同源策略是浏览器安全的基石。
同源策略是一种约定,它是浏览器最核心也最基本的安全功能。
所谓同源(即指在同一个域)就是两个页面具有相同的协议(protocol),主机(host)和端口号(port)。
当一个请求url的协议、域名、端口三者之间任意一个与当前页面url不同即为跨域,此时无法读取非同源网页的Cookie,无法向非同源地址发送Ajax请求或者Axios请求。
简单请求的服务器处理
非简单请求
对于非简单请求的跨源请求,浏览器会在真实请求发出前增加一次OPTION请求,称为预检请求(preflight request)。
预检请求将真实请求的信息,包括请求方法、自定义头字段、源信息添加到HTTP头信息字段中,询问服务器是否允许这样的操作。
例如一个GET请求:
Access-Control-Request-Method表示请求使用的HTTP方法,Access-Control-Request-Headers包含请求的自定义头字段。
服务器收到请求时,需要分别对Origin、Access-Control-Request-Method、Access-Control-Request-Headers进行验证,验证通过后,会在返回HTTP头信息中添加:
@Configuration
public class CorsConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**") // 允许跨域访问的路径
.allowedOrigins("*") // 允许跨域访问的源
.allowedMethods("POST","GET","PUT","OPTIONS","DELETE") // 允许请求的方法
.maxAge(16800) // 预检间隔时间
.allowedHeaders("*") // 允许头部设置
.allowCredentials(true); // 是否发送Cookie
}
}
vue-router@3在vue2中使用
npm install vue-router@3
vue-router@4在vue3中使用
npm install vue-router@4
电视剧
电影
综艺
import VueRouter from "vue-router";
import Vue from "vue";
import Teleplay from '../components/Teleplay.vue'
import Film from '../components/Film.vue'
import Variety from '../components/Variety.vue'
// 将VueRouter设置为Vue组件
Vue.use(VueRouter)
const router = new VueRouter({
// 指定hash属性与组件的对应关系
routes:[
{path:'/teleplay',component:Teleplay},
{path:'/film',component:Film},
{path:'/variety',component:Variety}
]
})
export default router
import Vue from 'vue'
import App from './App.vue'
import router from './router/index'
Vue.config.productionTip = false
new Vue({
render: h => h(App),
// router: router // 如果名称和属性一致可以直接写router即可
router
}).$mount('#app')
// 将VueRouter设置为Vue组件
Vue.use(VueRouter)
const router = new VueRouter({
// 指定hash属性与组件的对应关系
routes:[
// 当用户访问时,直接跳转访问teleplay
{path:'/',redirect:'/teleplay'},
{path:'/teleplay',component:Teleplay},
{path:'/film',component:Film},
{path:'/variety',component:Variety}
]
})
export default router
电视剧
推荐
最新
const router = new VueRouter({
// 指定hash属性与组件的对应关系
routes:[
// 当用户访问时,直接跳转访问teleplay
{path:'/',redirect:'/teleplay'},
{
path:'/teleplay',
component:Teleplay,
// 通过children属性,嵌套声明子路由
children:[
{path:'toplist',component: Toplist},
{path:'newlist',component: Newlist}
]
},
{path:'/film',component:Film},
{path:'/variety',component:Variety},
]
})
export default router
声明式 | 编程式 |
---|---|
router.push(...) |
电影
电影1
电影2
电影3
router.beforeEach((to,from,next)=>{
if(to.path === '/main' && !isAuthenticated){
next('/login');
}else{
next();
}
});
这是vue2版本
npm install vuex@3
这是vue3版本
npm install vuex@4
import Vue from "vue";
import Vuex from "vuex";
Vue.use(Vuex);
const store = new Vuex.Store({
state:{
count:0,
},
mutations:{
increment(state){
state.count++;
}
}
})
export default store;
// 导入store
import store from './store/index'
new Vue({
render: h => h(App),
store:store
}).$mount('#app')
const store = new Vuex.Store({
state:{
count:0
},
mutations:{
increment(state){
state.count++;
}
}
})
TestStore
{{this.$store.state.count}}
import {mapState} from 'vuex'
export default{
name: 'TestStore',
computed: mapState({
// 箭头函数可使代码更加简练
count: state => state.count,
// 传字符串参数 'count' 等同于 'state => state.count'
countAlias: 'count',
// 为了能够使用'this'获取局部状态,必须使用常规函数
countPlusLocalState(state){
return state.count + this.localCount
}
})
}
computed: mapState([
// 映射 this.count 为 store.state.count
'count'
])
computed:{
// 这是自定义的一个计算属性
localComputed(){....},
// 使用对象展开运算符("...")将此对象混入到外部对象中
...mapState({
// ...
})
}
const store = new Vuex.Store({
state:{
todos:[
{id:1,text:"吃饭",done:true},
{id:2,text:"睡觉",done:false}
]
},
getters:{
doneTodos: (state) => {
return state.todos.filter(todo => todo.done===false);
}
}
})
const store = new Vuex.Store({
state:{
count:0
},
mutations:{
increment(state){
state.count++;
}
}
})
methods: {
increment(){
this.$store.commit('increment')
console.log(this.$store.state.count)
}
}
methods:{
...mapMutations([
'increment', // 将'this.increment()'映射为'this.$store.commit('increment')'
// 'mapMutations'也支持载荷:(可以传入额外的参数,即为载荷)
'incrementBy' // 将'this.incrementBy(amount)'映射为'this.$store.commit('incrementBy',amount)'
]),
}
const store = createStore({
state: {
count: 0;
},
mutations: {
increment(state){
state.count ++;
}
},
actions: {
increment(context){
context.commit('increment');
}
}
})
methods:{
...mapActions([
'increment', // 将'this.increment()' 映射为 'this.$store.dispatch('increment')'
// 'mapActions' 也支持载荷:
'incrementBy' // 将 'this.incrementBy(amount)' 映射为 'this.$store.dispatch('incrementBy',amount)'
]),
...mapActions({
add: 'increment' // 将'this.add()' 映射为 'this.$store.dispatch('increment')'
})
}
const moduleA = {
state: ()=>({...}),
mutations: {...},
actions:{...},
getters: {...}
}
const moduleB = {
state: ()=>({...}),
mutations: {...},
actions:{...}
}
const store = createStore({
modules: {
a: moduleA,
b: moduleB
}
})
store.state.a // ——>moduleA的状态
store.state.b // ——>moduleB的状态
npm install mockjs
// 引入mock.js
import Mock from 'mockjs'
// 设置延迟时间
// Mock.setup({
// timeout: 400
// })
// 使用mock.js模拟数据
Mock.mock('/product/search',{
"ret": 0,
"data":
{
"mtime": "@datatime", // 随机生成日期时间
"score|1-800": 800, // 随机生成1-800的数字
"rank|1-100": 100, // 随机生成1-100的数字
"stars|1-5": 5, // 随机生成1-5的数字
"nickname": "@cname", // 随机生成中文名字
"img": "@image('200x100','#ffcc33','#FFF','png','Fast Mock')"
// 尺寸 背景颜色 文字颜色 图片格式 图片文字
}
})
import './mock/index'
import axios from 'axios'
export default{
mounted:function(){
axios.get("/product/search")
.then(res=>{
console.log(res)
})
}
}
// 延时400ms请求到数据
Mock.setup({
timeout: 400
})
// 延时200-600ms请求到数据
Mock.setup({
timeout: '200-600'
})
// 属性名 name
// 生成规则 rule
// 属性值 value
'name|rule': value
互联网服务离不开用户认证。一般是一下流程:
Token是在服务端产生的一串字符串,是客户端访问资源接口(API)时所需要的资源凭证,流程如下:
io.jsonwebtoken
jjwt
0.9.1
public class JwtUtil {
// 7天过期
private static long expire = 604800;
// 32位秘钥
private static String secret = "abcdfghiabcdfghiabcdfghiabcdfghi";
// 生成token
public static String generateToken(String username){
Date now = new Date();
Date expiration = new Date(now.getTime() + 1000 * expire);
return Jwts.builder()
.setHeaderParam("type","JWT") // 设置Header
.setSubject(username) // 设置负载
.setIssuedAt(now) // 设置生效时间
.setExpiration(expiration) // 设置过期时间
.signWith(SignatureAlgorithm.HS512,secret) // 指定签名算法
.compact();
}
// 解析token
public static Claims getClaimsByToken(String token){
return Jwts.parser()
.setSigningKey(secret) // 传密钥,查看是否有篡改
.parseClaimsJws(token) // token是否正确
.getBody();
}
}
# 查找 是否安装了mariadb
rpm -qa|grep mariadb
# mariadb-libs-5.5.52-1.el7.x86_64
# 卸载(版本根据自己系统自带的自行更改)
rpm -e mariadb-libs-5.5.52-1.el7.x86_64 --nodeps
解压MySQL
# 创建mysql安装包存放点
mkdir /usr/server/mysql
# 解压
tar xvf mysql-5.7.34-1.el7.x86_64.rpm-bundle.tar
执行安装
# 切换到安装目录
cd /usr/server/mysql/
yum -y install libaio
yum -y install libncurses*
yum -y install perl perl-devel
# 安装
rpm -ivh mysql-community-common-5.7.34-1.el7.x86_64.rpm
rpm -ivh mysql-community-libs-5.7.34-1.el7.x86_64.rpm
rpm -ivh mysql-community-client-5.7.34-1.el7.x86_64.rpm
rpm -ivh mysql-community-server-5.7.34-1.el7.x86_64.rpm
启动MySQL
修改初始的随机密码
# 登录mysql
mysql -u root -p
Enter password: #输入在日志中生成的临时密码
# 更新root密码 设置为root(密码自行定义,后面远程连接需要用到)
set global validate_password_policy=0;
set global validate_password_length=1;
set password=password('root');
授予远程连接权限
# 让数据库支持远程连接
grant all privileges on *.* to 'root' @'%' identified by 'root';
# 刷新
flush privileges;
控制命令
#mysql的启动和关闭 状态查看
systemctl stop mysqld
systemctl status mysqld
systemctl start mysqld
#建议设置为开机自启动服务
systemctl enable mysqld
#查看是否已经设置自启动成功
systemctl list-unit-files | grep mysqld
关闭防火墙
firewall-cmd --state #查看防火墙状态
systemctl stop firewalld.service #停止firewall
systemctl disable firewalld.service #禁止firewall开机启动
yum install epel-release
yum update
yum -y install nginx
systemctl start nginx #开启nginx服务
systemctl stop nginx #停止nginx服务
systemctl restart nginx #重启nginx服务
tar -zvxf jdk-8u131-linux-x64.tar.gz
vi /etc/profile
# 文件末尾增加
export JAVA_HOME=/usr/server/jdk1.8.0_351
export PATH=${JAVA_HOME}/bin:$PATH
source /etc/profile
java -version
npm run build
server {
listen 80;
server_name locahost;
location / {
root /usr/app/dist;
index index.html;
}
}
nginx -s reload
# 表示让java程序在后台运行,然后生成运行日志,方便查看项目是否报错。
nohup java -jar shop-0.0.1-SNAPSHOT.jar > logName.log 2>&1 &
项目正常运行了,说明部署成功了,这样项目所有人就可以访问了。