文章目录
1. Web端
1.1 关于页面的一些布局
- vue页面一般格式
<template>
<NavBar /> //导航栏
<router-view/> //路由根据网址显示出不同的页面
</template>
<script>
import 'bootstrap/dist/css/bootstrap.css';
import 'bootstrap/dist/js/bootstrap';
import NavBar from './components/NavBar';
export default {
name: "App",
components: {
NavBar,
},
}
</script>
<style scope>
body {
background-image: url("https://s2.loli.net/2022/10/21/B5trdcDzO42JVKM.jpg");
background-size: cover;
}
</style>
- 引入bootstrap的头文件,在vue的app主页面引入即可
import 'bootstrap/dist/css/bootstrap.css';
import 'bootstrap/dist/js/bootstrap';
- 修改背景图片
background-image: url("背景图片地址");
background-size: cover;
1.2 关于Router的使用
- /:catchAll(.*)表示所有链接
- path为通过什么链接来访问该页面
- name为该页面的别名
- redirect为重定向到那个链接
- component 和 import导入名字对应
- meta是自定义的一个功能用于页面的授权访问
- /:id/ -->表示id是参数
import { createRouter, createWebHistory } from 'vue-router'
// 用到什么页面就引入什么页面
import PKIndexView from '../views/pk/PKIndexView'
import NotFound from '../views/error/NotFound'
const routes = [
{
path: "/",
name: "home",
redirect: "/pk/",
meta: {
requestAuth: true,
},
},
{
path: "/pk/:id/",
name: "pk_index",
component: PKIndexView,
meta: {
requestAuth: true,
},
},
{
path: "/404/",
name: "404",
component: NotFound,
meta: {
requestAuth: false,
},
},
{
path: "/:catchAll(.*)",
redirect: "/404/",
},
]
const router = createRouter({
history: createWebHistory(),
routes
})
router.beforeEach((to, from, next) => {
if (to.meta.requestAuth && !store.state.user.is_login) {
next({name: 'user_account_login'});
} else {
next();
}
})
export default router
- 该函数为访问所有页面前执行的函数
- router.push({name: ‘路由的别名’,params: {参数x:实参x}}); --> 在任意页面这么写都可实现页面跳转(头文件需引入该页面)
router.beforeEach((to, from, next) => {
if (to.meta.requestAuth && !store.state.user.is_login) {
next({name: 'user_account_login'});
} else {
next();
}
1.3 一些细节
1.3.1 active
- 那个标签class含有active那个标签被选中在bootstrap中
1.3.2 v-model
- 在标签中使用这可让标签里面的内容与某个属性绑定在一起
1.3.3 localStorage的使用
localStorage.setItem("jwt_token", resp.token);
localStorage.removeItem("jwt_token");
localStorage.getItem("jwt_token");
1.3.4 store的使用
- commit用于修改全局变量访问mutations中的方法,同步
- dispatch用于访问actions中的方法,异步
store.commit('updateToken', jwt_token);
store.dispatch("getinfo", {
success() {
router.push({name: 'home'});
store.commit("updatePullingInfo", false);
},
error() {
store.commit("updatePullingInfo", false);
}
});
1.3.5 JSON的使用
- stringify用于将json转为字符串(用于数据传输)
JSON.stringify({
event: "move",
direction: d,
})
- parse用于将json的字符串转换为json
JSON.parse(msg.data)
1.3.6 v-for的使用
- v-for要绑定id
v-for="user in users" :key="user.user.id"
1.3.7 代码编辑框和模态框
- Modal模态框通过id隐藏
import { Modal } from 'bootstrap/dist/js/bootstrap';
Modal.getInstance("#add-bot-btn").hide();
- 代码编辑框安装依赖:
vue3-ace-editor
import { VAceEditor } from 'vue3-ace-editor';
import ace from 'ace-builds';
ace.config.set(
"basePath",
"https://cdn.jsdelivr.net/npm/ace-builds@" + require('ace-builds').version + "/src-noconflict/")
<VAceEditor
v-model:value="botadd.content"
@init="editorInit"
lang="c_cpp"
theme="textmate"
style="height: 300px" />
1.3.8 页面加载和卸载
onMounted
页面加载(进入页面),onUnmounted
页面卸载(离开页面)
import { onMounted, onUnmounted } from 'vue';
onMounted(页面加载时执行的函数);
onUnmounted(页面卸载时执行函数);
1.3.9 WebSocket协议(双端通信)
- 定义:
let socket = new WebSocket(socketUrl);
- 主要接口:分别对应连接前,断开后,和接收消息(msg: json的string形式)
socket.onopen = () => {
console.log("connection");
store.commit("updateSocket", socket);
};
socket.onclose = () => {
console.log("distconnection");
};
socket.onmessage = msg => {
}
- 发送消息:
socket.send(JSON.stringify({json}));
1.3.10 导航栏
- 链接页面展示:
<router-view/>
- 链接引用:
<router-link :to="{name: 'router里页面定义的名字'}" />
1.3.11 Route(获取链接)
- myRouter.name:可用于获取当前链接的别名
- myRouter.query.x:可用于获取当前链接的参数x
import { useRoute } from 'vue-router';
const myRouter = useRoute();
1.3.12 computed (动态计算)
import { computed } from '@vue/reactivity';
let route_name = computed(() => route.name);
1.3.13 ajax访问jwt授权url时需加上以下内容
headers: {
Authorization: "Bearer " + token,
},
2. 后端
2.1 pom.xml中一些常用的依赖
2.1.1 mysql连接的驱动
MySQL Connector/J
<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.29</version>
</dependency>
2.1.2 JDBC的实现
Spring Boot Starter JDBC
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-jdbc -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
<version>2.7.1</version>
</dependency>
- application.properties配置jdbc的连接。
spring.datasource.username=root
spring.datasource.password=***
spring.datasource.url=jdbc:mysql://localhost:3306/kob?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf-8
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver //mysql-8版本
spring.datasource.driver-class-name=com.mysql.jdbc.Driver //mysql-5版本
2.1.3 一个类的基本方法的实现(get,set …)
Project Lombok
<!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.24</version>
<scope>provided</scope>
</dependency>
2.1.4 数据库基本操作curd的实现
mybatis-plus-boot-starter
mybatis-plus-generator
<!-- https://mvnrepository.com/artifact/com.baomidou/mybatis-plus-boot-starter -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.baomidou/mybatis-plus-generator -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>3.5.3</version>
</dependency>
2.1.5 安全机制的实现
spring-boot-starter-security
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-security -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
<version>2.7.1</version>
</dependency>
- 默认情况会封锁所有的url,登录账号为user、密码为项目启动是随机生成的字符串,若要更改登录为查询数据库账号密码需实现以下两个类:
- ①
UserDetailsServiceImpl
、②UserDetailsImpl
@Service
public class UserDetailsServiceImpl implements UserDetailsService {
@Autowired
private UserMapper userMapper;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("username", username);
User user = userMapper.selectOne(queryWrapper);
if (user == null) {
throw new RuntimeException("无该用户");
}
return new UserDetailsImpl(user);
}
}
@Data
@NoArgsConstructor
@AllArgsConstructor
public class UserDetailsImpl implements UserDetails {
private User user;
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return null;
}
@Override
public String getPassword() {
return user.getPassword();
}
@Override
public String getUsername() {
return user.getUsername();
}
@Override
public boolean isAccountNonExpired() {//账户是否没有过期
return true;
}
@Override
public boolean isAccountNonLocked() {//账户是否没有被锁定
return true;
}
@Override
public boolean isCredentialsNonExpired() {//授权是否没有过期
return true;
}
@Override
public boolean isEnabled() {//是否被启用
return true;
}
}
- 注: 在查询数据库密码时,会涉及到密码的存储方式问题
{noop}***
表示该密码***是明文密码,不加默认认为是密文。 - 加密算法需自己在配置类中实现
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
补充:PasswordEncoder 的方法
①encode("xxx")
为加密字符串xxx
。
② matches("aaa", "bbb")
为判断bbb
是否是aaa
的加密字符串。
2.1.6 jwt验证
jjwt-api
jjwt-impl
jjwt-jackson
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-api</artifactId>
<version>0.11.5</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-impl</artifactId>
<version>0.11.5</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-jackson</artifactId>
<version>0.11.5</version>
<scope>runtime</scope>
</dependency>
- 登录时用于通过账号密码获取认证和
jwt
UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken
= new UsernamePasswordAuthenticationToken(username, password);
//登录失败自动处理
Authentication authenticate = authenticationManager.authenticate(usernamePasswordAuthenticationToken);
UserDetailsImpl loginUser = (UserDetailsImpl)authenticate.getPrincipal();
User user = loginUser.getUser();
String jwt = JwtUtil.createJWT(user.getId().toString());
- 在授权成功后通过上下文获取
user
。
UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken =
(UsernamePasswordAuthenticationToken) SecurityContextHolder.getContext().getAuthentication();
UserDetailsImpl loginUser = (UserDetailsImpl) usernamePasswordAuthenticationToken.getPrincipal();
User user = loginUser.getUser();
2.1.7 websocket
spring-boot-starter-websocket
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
<version>2.7.2</version>
</dependency>
2.1.8 json
fastjson
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>2.0.11</version>
</dependency>
2.1.9 joor(动态编译、执行Java代码)
joor-java-8
<dependency>
<groupId>org.jooq</groupId>
<artifactId>joor-java-8</artifactId>
<version>0.9.14</version>
</dependency>
2.1.10 httpclient
httpclient
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.13</version>
</dependency>
2.1.11 redis
spring-boot-starter-data-redis
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<version>2.7.5</version>
</dependency>
2.2 在SpringBoot中的一些配置
2.2.1 解决跨域的配置
- 添加配置类:
CorsConfig
。
import org.springframework.context.annotation.Configuration;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@Configuration
public class CorsConfig implements Filter {
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletResponse response = (HttpServletResponse) res;
HttpServletRequest request = (HttpServletRequest) req;
String origin = request.getHeader("Origin");
if(origin!=null) {
response.setHeader("Access-Control-Allow-Origin", origin);
}
String headers = request.getHeader("Access-Control-Request-Headers");
if(headers!=null) {
response.setHeader("Access-Control-Allow-Headers", headers);
response.setHeader("Access-Control-Expose-Headers", headers);
}
response.setHeader("Access-Control-Allow-Methods", "*");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Credentials", "true");
chain.doFilter(request, response);
}
@Override
public void init(FilterConfig filterConfig) {
}
@Override
public void destroy() {
}
}
2.2.2 jwt认证的配置
- 实现
utils.JwtUtil
类,为jwt
工具类,用来创建、解析jwt token
,其中有两个常用方法createJWT(id)
通过id
获取jwt
,parseJWT(jwt)
通过jwt
获取id
。
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.stereotype.Component;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.util.Base64;
import java.util.Date;
import java.util.UUID;
@Component
public class JwtUtil {
public static final long JWT_TTL = 60 * 60 * 1000L * 24 * 14; // 有效期14天
public static final String JWT_KEY = "SDFGjhdsfalshdfHFdsjkdsfds121232131afasdfac"; //密钥用的时候改一下不能太短,不能给别人看
public static String getUUID() {
return UUID.randomUUID().toString().replaceAll("-", "");
}
public static String createJWT(String subject) {
JwtBuilder builder = getJwtBuilder(subject, null, getUUID());
return builder.compact();
}
private static JwtBuilder getJwtBuilder(String subject, Long ttlMillis, String uuid) {
SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
SecretKey secretKey = generalKey();
long nowMillis = System.currentTimeMillis();
Date now = new Date(nowMillis);
if (ttlMillis == null) {
ttlMillis = JwtUtil.JWT_TTL;
}
long expMillis = nowMillis + ttlMillis;
Date expDate = new Date(expMillis);
return Jwts.builder()
.setId(uuid)
.setSubject(subject)
.setIssuer("sg")
.setIssuedAt(now)
.signWith(signatureAlgorithm, secretKey)
.setExpiration(expDate);
}
public static SecretKey generalKey() {
byte[] encodeKey = Base64.getDecoder().decode(JwtUtil.JWT_KEY);
return new SecretKeySpec(encodeKey, 0, encodeKey.length, "HmacSHA256");
}
public static Claims parseJWT(String jwt) throws Exception {
SecretKey secretKey = generalKey();
return Jwts.parserBuilder()
.setSigningKey(secretKey)
.build()
.parseClaimsJws(jwt)
.getBody();
}
}
- 实现
config.filter.JwtAuthenticationTokenFilter
类,用来验证jwt token
,如果验证成功,则将User
信息注入上下文中。
import com.kob.backend.mapper.UserMapper;
import com.kob.backend.pojo.User;
import com.kob.backend.service.impl.utils.UserDetailsImpl;
import com.kob.backend.utils.JwtUtil;
import io.jsonwebtoken.Claims;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@Component
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {
@Autowired
private UserMapper userMapper;
@Override
protected void doFilterInternal(HttpServletRequest request, @NotNull HttpServletResponse response, @NotNull FilterChain filterChain) throws ServletException, IOException {
String token = request.getHeader("Authorization");
if (!StringUtils.hasText(token) || !token.startsWith("Bearer ")) {
filterChain.doFilter(request, response);
return;
}
token = token.substring(7);
String userid;
try {
Claims claims = JwtUtil.parseJWT(token);
userid = claims.getSubject();
} catch (Exception e) {
throw new RuntimeException(e);
}
User user = userMapper.selectById(Integer.parseInt(userid));
if (user == null) {
throw new RuntimeException("用户名未登录");
}
UserDetailsImpl loginUser = new UserDetailsImpl(user);
UsernamePasswordAuthenticationToken authenticationToken =
new UsernamePasswordAuthenticationToken(loginUser, null, null);
SecurityContextHolder.getContext().setAuthentication(authenticationToken);
filterChain.doFilter(request, response);
}
}
- 配置
config.SecurityConfig
类,放行登录、注册等接口。
import com.kob.backend.config.filter.JwtAuthenticationTokenFilter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter;
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
.antMatchers("/user/account/token/", "/user/account/register/").permitAll()
.antMatchers(HttpMethod.OPTIONS).permitAll()
.anyRequest().authenticated();
http.addFilterBefore(jwtAuthenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);
}
}
2.2.3 分页的配置
@Configuration
public class MybatisConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
return interceptor;
}
}
- 用法
IPage<User> iPage = new Page<>(page, 8);
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.orderByDesc("rating");
List<User> users = userMapper.selectPage(iPage, queryWrapper).getRecords();
2.2.4 HttpClient的配置
import org.apache.http.HttpEntity;
import org.apache.http.NameValuePair;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import java.io.IOException;
import java.net.URISyntaxException;
import java.util.List;
public class HttpClientUtil {
public static String get(String url, List<NameValuePair> params) {
URIBuilder uriBuilder = null;
try {
uriBuilder = new URIBuilder(url);
} catch (URISyntaxException e) {
e.printStackTrace();
return null;
}
uriBuilder.setParameters(params);
try (CloseableHttpClient client = HttpClients.createDefault()) {
HttpGet httpGet = new HttpGet(uriBuilder.build());
CloseableHttpResponse response = client.execute(httpGet);
HttpEntity entity = response.getEntity();
return EntityUtils.toString(entity);
} catch (IOException | URISyntaxException e) {
e.printStackTrace();
return null;
}
}
}
用法:
List<NameValuePair> list = new ArrayList<>();
list.add(new BasicNameValuePair("appid", appId));
list.add(new BasicNameValuePair("secret", appSecret));
list.add(new BasicNameValuePair("code", code));
String data = HttpClientUtil.get(applyAccessTokenUrl, list);
2.3 各种注意事项
- 在数据库中名称为
user_id
是在实体类需写成userId
。 - 在自增的属性上加注解
@TableId(type = IdType.AUTO)
。 - 在时间的属性
java.util.Date
上加注解@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone="Asia/Shanghai")
。 - 当静态属性需要注入时,需使用set注入,并且所有注入(包括非静态注入)都需要在该类上面加注解一般为
@Component
特殊情况使用别的。 - 在动态执行Java代码时需单开一个线程执行避免死循环
this.start();
try{
this.join(timeout);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
this.interrupt();
}
2.4 写项目时用的的一些类
2.4.1 WebSocket
- 添加配置类
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;
@Configuration
public class WebSocketConfig {
@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
}
- 添加
WebSocketServer
类- 一个类在添加
@ServerEndpoint
注解后该类为websocket类。 - 每建立一个websocket连接相当于创建一个该类的对象。
@ServerEndpoint("/websocket/{token}")
:为第一步配置类所配置的websocket注解,里面的内容为访问该websocket的url。- 后端向前端发送消息要使用一开始建立连接时的
session
。注意这里的session是websocket包下的
- 一个类在添加
import org.springframework.stereotype.Component;
import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
@Component
@ServerEndpoint("/websocket/{token}") // 注意不要以'/'结尾
public class WebSocketServer {
private Session session = null;
@OnOpen
public void onOpen(Session session, @PathParam("token") String token) {
// 建立连接
this.session= session;
}
@OnClose
public void onClose() {
// 关闭链接
}
@OnMessage
public void onMessage(String message, Session session) {
// 从Client接收消息
}
@OnError
public void onError(Session session, Throwable error) {
error.printStackTrace();
}
public void sendMessage(String message) {
// 发送消息给远程连接
synchronized (this.session) {
try {
this.session.getBasicRemote().sendText(message);
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
- security中放行websocket的所有链接
- 配置
config.SecurityConfig
- 配置
@Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/websocket/**");
}
2.4.2 RestTemplate(服务器之间通信、访问HTTP协议)
- 配置
RestTemplateConfig
类,使其可以被注入
@Configuration
public class RestTemplateConfig {
@Bean
public RestTemplate getRestTemplate() {
return new RestTemplate();
}
}
- RestTemplate中一些方法的详解: https://zhuanlan.zhihu.com/p/31681913
- 本项目用到的方法:postForObject(url, data, class)
- url:请求地址。
- data:请求参数。(这儿如果使用
map
需使用MultiValueMap
) - class:返回值的类型对应的class。
2.4.3 ReentrantLock
- 用途:处理多线程读写冲突
- 定义:
ReentrantLock lock = new ReentrantLock()
- 使用
lock.lock();
try {
// 执行的语句
} finally {
lock.unlock();
}
2.4.4 JSONObject
- 定义:
JSONObject resp = new JSONObject();
- string->json:
resp = JSONObject.parseObject(message);
- json->string:
String message = resp.toJSONString();
2.4.5 Reflect
- 导包:
import org.joor.Reflect;
- 使用:
Reflect.compile(
name, // 编译的类名
content // 编译的类的内容
).create(
// 构造方法的参数
).get(); //获得该类的对象
2.4.6 UUID(用于获取一个随机字符串)
- 配合Reflect来使用Reflect动态编译一个类每次类名不能重复因此需要在类名后加一个随机值。
- 导包:
import java.util.UUID;
UUID uuid = UUID.randomUUID();
String id = uuid.toString();
2.6.7 Condition
private final ReentrantLock lock = new ReentrantLock();
private final Condition condition = lock.newCondition();
condition.await(); // 释放锁并且该线程阻塞
condition.signalAll(); // 唤醒所有阻塞(await)的线程
2.6.8 Redis
- 在
Linux
服务器中启动redis
:sudo redis-server /etc/redis/redis.conf
- 在application.properties文件中的配置
spring.redis.host=localhost
spring.redis.port=6379
- 用法:
@Autowired
private RedisTemplate<String, String> redisTemplate;
redisTemplate.opsForValue().set(state.toString(), "true");
redisTemplate.expire(state.toString(), Duration.ofMinutes(10)); //过期时间为10分钟
Boolean.FALSE.equals(redisTemplate.hasKey(state) //判断state是否存在/过期
2.5 Ubuntu下安装软件
2.5.1 mysql
- 安装:
sudo apt-get install mysql-server
- 启动:
sudo service mysql start
- 设置
root
用户的密码:ALTER USER 'root'@'localhost' IDENTIFIED WITH caching_sha2_password BY 'yourpasswd';
- 执行sql脚本:
source xxx.sql;
2.5.2 jdk
- 安装java8:
ALTER USER 'root'@'localhost' IDENTIFIED WITH caching_sha2_password BY 'yourpasswd';
2.6 项目上线
- 将后端代码打包成jar文件
<packaging>jar</packaging>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<!--这里写上main方法所在类的路径-->
<configuration>
<mainClass>com.kob.backend.BackendApplication</mainClass>
</configuration>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
- idea打包后端项目示例:先点击clean再点击package
- 打包之后会在对应项目文件下的target目录下生成xxx.jar文件
- 在linux服务器上输入
java -jar xxx.jar
运行该项目