SpringBoot项目搭建 + Jwt登录
临时接了一个小项目,有需要搭一个小项目,简单记录一下项目搭建过程以及整合登录功能。
1.首先拿到的是一个码云地址,里面是一个空的文件夹,只有一个

2. 拿到HTTPS码云项目地址链接,在IDEA中clone输入项目地址

3. 在项目根目录文件夹下右击,选择Add Frameworks Support, 添加maven框架支持

4. 然后得到pom.xml文件, 在pom文件中配置springboot
点击查看代码
<groupId>groupId</groupId>
<artifactId>resource-manager-background</artifactId>
<version>1.0-SNAPSHOT</version>
<parent>
<artifactId>spring-boot-starter-parent</artifactId>
<groupId>org.springframework.boot</groupId>
<version>2.3.12.RELEASE</version>
</parent>
5. 引入其他相关依赖 mysql druid mybatisplus
点击查看代码
<dependencies>
<!-- mysqlconnect -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.2.1</version>
</dependency>
<!-- Mybatis-plus -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.0</version>
</dependency>
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
<version>1.2.12</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>3.4.0</version>
</dependency>
<!-- jwt -->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
</dependency>
<!-- security -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<!-- springweb -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<swagger2.version>2.9.2</swagger2.version>
</properties>
6. 创建security文件夹,创建Security核心配置类
点击查看代码
package com.gameresource.security.config;
import com.gameresource.base.bean.Resp;
import com.gameresource.base.constant.RespConstant;
import com.gameresource.security.filter.JwtAuthTokenFilter;
import com.gameresource.security.util.RespUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer;
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;
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private IgnoreUrlsConfig ignoreUrlsConfig;
@Override
protected void configure(HttpSecurity http) throws Exception {
ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry registry = http.authorizeRequests();
for (String url : ignoreUrlsConfig.getUrls()) {
registry.antMatchers(url).permitAll();
}
registry.antMatchers(HttpMethod.OPTIONS).permitAll();
registry.and()
.authorizeRequests()
.anyRequest()
.authenticated()
//关闭跨站请求防护及不使用防护
.and()
.csrf()
.disable()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
//自定义权限拒绝处理类
.and()
.exceptionHandling()
.accessDeniedHandler(((request, response, accessDeniedException) -> {
RespUtils.outJson(response, Resp.code(RespConstant.NOT_PERMISSION));
}))
.authenticationEntryPoint((request, response, authenticationException) -> {
RespUtils.outJson(response, Resp.code(RespConstant.NOT_AUTHORIZE));
})
//自定义权限拦截器JWT过滤器
.and()
.addFilterBefore(jwtAuthTokenFilter(), UsernamePasswordAuthenticationFilter.class);
//关闭默认登录
http.formLogin().disable().httpBasic().disable();
}
@Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers(
"/auth/login",
"/doc.html",
"/swagger-ui.html",
"/v2/api-docs",
"/swagger-resources/**",
"/**/*.js",
"/**/*.css",
"/**/*.png",
"/**/*.ico"
);
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
public JwtAuthTokenFilter jwtAuthTokenFilter() {
return new JwtAuthTokenFilter();
}
}
7. 自定义JWT过滤器
点击查看代码
package com.gameresource.security.filter;
import cn.hutool.core.util.StrUtil;
import com.gameresource.base.bean.Resp;
import com.gameresource.base.constant.RespConstant;
import com.gameresource.security.constant.SecurityConstant;
import com.gameresource.security.config.IgnoreUrlsConfig;
import com.gameresource.security.util.JwtTokenUtil;
import com.gameresource.security.util.RespUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
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;
/**
* 自定义JWT过滤器
*/
@Slf4j
public class JwtAuthTokenFilter extends OncePerRequestFilter {
@Autowired
private UserDetailsService userDetailsService;
@Autowired
private IgnoreUrlsConfig ignoreUrlsConfig;
@Autowired
private JwtTokenUtil jwtTokenUtil;
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException {
String authHeader = request.getHeader(SecurityConstant.TOKEN_HEADER);
String uri = request.getRequestURI();
if (StrUtil.startWith(authHeader, SecurityConstant.TOKEN_HEAD)) {
try {
String token = StrUtil.trim(authHeader.substring(SecurityConstant.TOKEN_HEAD.length()));
String username = jwtTokenUtil.getUserNameFromToken(token);
log.info("checking username:{}", username);
if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
if (jwtTokenUtil.validateToken(token)) {
UserDetails userDetails = userDetailsService.loadUserByUsername(username);
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
log.info("pass user: {}", username);
SecurityContextHolder.getContext().setAuthentication(authenticationToken);
}
}
} catch (BadCredentialsException exception) {
RespUtils.outJson(response, Resp.fail(exception.getMessage()));
return;
} catch (Exception exception) {
log.error("Spring Security 校验异常: ", exception);
RespUtils.outJson(response, Resp.code(RespConstant.NOT_AUTHORIZE));
return;
}
}
chain.doFilter(request, response);
}
}
8. 创建JWT工具类
点击查看代码
package com.gameresource.security.util;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.gameresource.security.constant.SecurityConstant;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import lombok.Data;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Component;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
/**
* jwt工具类
*/
@Slf4j
@Component
@RequiredArgsConstructor
public class JwtTokenUtil {
@Value("${project.name}")
private String projectName;
@Value("${Jwt.secret}")
private String secret;
@Value("${Jwt.expiration}")
private Integer expiration;
private final StringRedisTemplate redisTemplate;
public boolean validateToken(String token) {
String username = getUserNameFromToken(token);
String redisKey = TokenRedisKeyUtils.installAuthToken(projectName, username);
if (Boolean.FALSE.equals(redisTemplate.hasKey(redisKey))) {
throw new BadCredentialsException("Token不存在或已过期");
}
String redisToken = redisTemplate.opsForValue().get(redisKey);
if (!StrUtil.equals(redisToken, token)) {
throw new BadCredentialsException("无效token");
}
return true;
}
/**
* 从token中获取用户名
*/
public String getUserNameFromToken(String token) {
return Convert.toStr(getValueFromToken(token, SecurityConstant.CLAIM_KEY_USERNAME));
}
private Object getValueFromToken(String token, String key) {
Claims claim = getClaimsFromToken(token);
return claim != null ? claim.get(key) : null;
}
private Claims getClaimsFromToken(String token) {
Claims claims = null;
try {
claims = Jwts.parser()
.setSigningKey(secret)
.parseClaimsJws(token)
.getBody();
} catch (Exception exception) {
log.error("jwt格式验证失败: {}", token);
}
return claims;
}
public String generateToken(UserDetails userDetails) {
return generateToken(userDetails, null);
}
private String generateToken(UserDetails userDetails, Map<String, Object> claims) {
if (claims == null) {
claims = new HashMap<>();
}
claims.put(SecurityConstant.CLAIM_KEY_USERNAME, userDetails.getUsername());
int ttl = expiration * 1000;
DateTime dateTime = DateUtil.offsetMillisecond(new Date(), ttl);
String token = Jwts.builder()
.setClaims(claims)
.setExpiration(dateTime)
.signWith(SignatureAlgorithm.HS256, secret)
.compact();
String redisKey = TokenRedisKeyUtils.installAuthToken(projectName, userDetails.getUsername());
redisTemplate.opsForValue().set(redisKey, token, ttl, TimeUnit.MILLISECONDS);
return token;
}
public Boolean removeToken(String username) {
return redisTemplate.delete(TokenRedisKeyUtils.installAuthToken(projectName, username));
}
}
9. 响应工具类
点击查看代码
package com.gameresource.security.util;
import com.alibaba.fastjson.JSON;
import com.gameresource.base.bean.Resp;
import org.springframework.http.MediaType;
import org.springframework.security.core.parameters.P;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
public class RespUtils {
public static void outJson(HttpServletResponse response, Resp resp) {
response.setContentType(MediaType.APPLICATION_JSON_VALUE);
response.setStatus(HttpServletResponse.SC_OK);
response.setCharacterEncoding("utf-8");
try (PrintWriter printWriter = response.getWriter();) {
printWriter.print(JSON.toJSONString(resp));
printWriter.flush();
}catch (IOException exception) {
throw new RuntimeException();
}
}
}
10. UserDetailsService的自定义
点击查看代码
package com.gameresource.security.service;
import com.gameresource.manage.sys.SysUserManager;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
@Service
@RequiredArgsConstructor
public class AuthUserDetailService implements UserDetailsService {
private final SysUserManager userManager;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
return userManager.findUserByName(username);
}
}
11. 各种类的实现代码
1. SysUserManager
点击查看代码
package com.gameresource.manage.sys;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.gameresource.module.sys.domain.AuthUser;
import com.gameresource.module.sys.entity.SysUserEntity;
import com.gameresource.module.sys.entity.SysUserRoleEntity;
import com.gameresource.module.sys.service.ISysUserRoleService;
import com.gameresource.module.sys.service.ISysUserService;
import com.gameresource.security.constant.SecurityConstant;
import com.gameresource.security.util.JwtTokenUtil;
import com.sun.org.apache.xpath.internal.operations.Bool;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import java.util.List;
import java.util.stream.Collectors;
@RequiredArgsConstructor
@Component
@Slf4j
public class SysUserManager {
private final ISysUserService userService;
@Autowired
private PasswordEncoder passwordEncoder;
private final ISysUserRoleService userRoleService;
private final JwtTokenUtil jwtTokenUtil;
public String login(String username, String password) {
UserDetails userDetails = findUserByName(username);
if (passwordEncoder.matches(password, userDetails.getPassword())) {
throw new BadCredentialsException("用户名或密码错误");
}
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
SecurityContextHolder.getContext().setAuthentication(authenticationToken);
return jwtTokenUtil.generateToken(userDetails);
}
public UserDetails findUserByName(String username) {
SysUserEntity userEntity = userService.getByUsername(username);
if (ObjectUtil.isNull(userEntity)) {
throw new UsernameNotFoundException("用户不存在!");
}
if (!userEntity.getStatus()) {
throw new RuntimeException("此账户已被禁用!");
}
List<SysUserRoleEntity> roleEntityList = userRoleService.getByUserId(userEntity.getId());
List<Integer> roleList = roleEntityList.stream().map(SysUserRoleEntity::getRoleId).collect(Collectors.toList());
return AuthUser.create(userEntity, roleList, null);
}
public boolean logout(HttpServletRequest request) {
String token = request.getHeader(SecurityConstant.TOKEN_HEADER);
if (StrUtil.isBlank(token)) {
return false;
}
token = token.substring(SecurityConstant.TOKEN_HEAD.length());
String username = jwtTokenUtil.getUserNameFromToken(token);
Boolean logout = jwtTokenUtil.removeToken(username);
if (!logout) {
log.error("============登出失败============");
}
log.info("=======================用户退出{}======================", username);
return true;
}
}
2. AuthUser
点击查看代码
package com.gameresource.module.sys.domain;
import cn.hutool.core.collection.CollUtil;
import com.gameresource.module.sys.entity.SysUserEntity;
import lombok.Data;
import lombok.experimental.Accessors;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
@Data
@Accessors(chain = true)
public class AuthUser implements UserDetails {
/**
* 用户id
*/
private int userId;
/**
* 用户名
*/
private String username;
/**
* 密码
*/
private String password;
/**
* 是否启用
*/
private boolean status;
/**
* 用户角色列表
*/
private List<Integer> roleIds;
/**
* 用户权限列表
*/
private Collection<? extends GrantedAuthority> authorities;
public static UserDetails create(SysUserEntity sysUser, List<Integer> roleIds, List<String> perms) {
if (sysUser == null) {
return null;
}
List<GrantedAuthority> authorities = Collections.emptyList();
if (CollUtil.isNotEmpty(perms)) {
authorities = perms.stream().map(SimpleGrantedAuthority::new).collect(Collectors.toList());
}
return new AuthUser()
.setUserId(sysUser.getId())
.setStatus(sysUser.getStatus())
.setUsername(sysUser.getUsername())
.setPassword(sysUser.getPassword())
.setRoleIds(CollUtil.isNotEmpty(roleIds) ? roleIds : Collections.emptyList())
.setAuthorities(authorities);
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return null;
}
@Override
public String getPassword() {
return password;
}
@Override
public String getUsername() {
return username;
}
@Override
public boolean isAccountNonExpired() {
return false;
}
@Override
public boolean isAccountNonLocked() {
return false;
}
@Override
public boolean isCredentialsNonExpired() {
return false;
}
@Override
public boolean isEnabled() {
return status;
}
}
12. 登录接口
点击查看代码
package com.gameresource.web.sys;
import cn.hutool.core.lang.Assert;
import com.gameresource.base.bean.Resp;
import com.gameresource.manage.sys.SysUserManager;
import com.gameresource.module.sys.domain.AuthUser;
import com.gameresource.module.sys.domain.AuthUserVo;
import com.gameresource.module.sys.domain.LoginReqDto;
import com.gameresource.util.SecurityUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;
@Slf4j
@Api(tags = "登录")
@RestController
@RequestMapping("/auth")
@RequiredArgsConstructor
public class LoginController {
private final SysUserManager sysUserManager;
@ApiOperation("用户登录")
@PostMapping("/login")
public Resp<AuthUserVo> login(@Valid @RequestBody LoginReqDto loginReq) {
try {
log.info("===============loginReq=====================username:[{}],password:[{}]",loginReq.getUsername(), loginReq.getPassword());
String token = sysUserManager.login(loginReq.getUsername(), loginReq.getPassword());
Assert.notBlank(token, "用户名或密码错误");
AuthUser authUser = SecurityUtil.getCurrentUser();
log.info("========================用户{}登录成功!=============================", authUser.getUsername());
return Resp.ok(AuthUserVo.create(authUser, token));
}catch (Exception e) {
log.info("登录失败: ", e);
return Resp.fail(e.getMessage());
}
}
@ApiOperation("用户退出")
@PostMapping("/logout")
public Resp<Boolean> logout(HttpServletRequest request) {
return Resp.result(sysUserManager.logout(request));
}
}
13. 至此结束
其实登录的核心部分就是WebSecurityConfigurerAdapter下的configure方法,我们通过自定义了一个SecurityConfig类来继承了WebSecurityConfigurerAdapter类,并重写配置类的各种选项达到自定义的效果,另外一个就是OncePerRequestFilter来过滤各种请求,在这里我们会处理请求并验证token,这只是项目中比较简单的一种写法,另外security还有很多其他的配置,在这里只是列举了其中的一种较为简单的方式,才疏学浅,还需要多加学习,共勉!
SpringBoot项目搭建 + Jwt登录的更多相关文章
- SpringBoot 项目搭建(详细介绍+案例源码)
SpringBoot 项目搭建 SpringBoot 项目整合源码 SpringBoot 项目整合 一.项目准备 1.1 快速创建 SpringBoot 项目 1.2 标准项目结构图如下 1.3 添加 ...
- SpringBoot之入门教程-SpringBoot项目搭建
SpringBoot大大的简化了Spring的配置,把Spring从配置炼狱中解救出来了,以前天天配置Spring和Mybatis,Springmvc,Hibernate等整合在一起,感觉用起来还是挺 ...
- SpringBoot项目搭建与打包
一.环境准备 本地java环境jdk1.8 Maven版本3.5.2 IDE工具idea2017 二.SpringBoot微服务搭建 1.点击File >> New >> Pr ...
- springboot系列二、springboot项目搭建
一.官网快速构建 1.maven构建项目 1.访问http://start.spring.io/ 2.选择构建工具Maven Project.Spring Boot版本2.1.1以及一些工程基本信息, ...
- 从零开始的SpringBoot项目搭建
前言 今天是我加入博客园的第一天今天刚好学习到SpringBoot,就顺便记录一下吧 一.创建项目 1.创建工程 ① 通过File > New > Project,新建工程,选择Sprin ...
- Springboot项目搭建(3)-shiro登录
shiro简述+实现简单登录:https://www.jianshu.com/p/7f724bec3dc3
- springboot项目搭建及常用技术整合
一.在你建立的工程下创建 Module 选择Spring initializr创建. 二.在Type处选择: Maven Project(项目的构建工具) 三.创建依赖时勾上web,mybatis,m ...
- oa_mvc_easyui_项目搭建及登录页面验证码(1)
1.空项目的搭建,三层的搭建(各层之中的引用) webapp:bll,model,common bll:dal,model dal:model 2.SQL表 ItcastDb:T_UserInfo,T ...
- springboot项目搭建:结构和入门程序
Spring Boot 推荐目录结构 代码层的结构 根目录:com.springboot 1.工程启动类(ApplicationServer.java)置于com.springboot.build包下 ...
随机推荐
- CVPR2022 | 重新审视池化:你的感受野不是最理想的
前言 本文提出了一种简单而有效的动态优化池操作( Dynamically Optimized Pooling operation),称为DynOPool,它通过学习每一层感受野的最佳大小和形状来优化特 ...
- DirectX11 With Windows SDK--19(Dev) 编译Assimp并加载模型、新的Effects框架
前言 注意:这一章进行了重写,对应教程Dev分支第19章的项目,在更新完后面的项目后会替换掉原来第19章的教程 在前面的章节中我们一直使用的是由代码生成的几何模型,但现在我们希望能够导入模型设计师生成 ...
- Eclipse For Java开发环境部署
Eclipse For Java开发环境部署 1.准备工作 jdk安装包 jdk官网下载 Eclipse安装包 Eclipse官网下载 Eclipse下载时选择图中所示的国内镜像地址下载 下载后的文件 ...
- 智慧机房3D可视化技术解决方案
随着夏季气温越来越高,机房内大量设备同步工作时,难免使机房内温度飙升. 机房温度每升高10℃,计算机的可靠性就下降25% 磁盘磁带也会因热涨效应造成记录错误 计算机的时钟主频在温度过高都会降低 UPS ...
- 实现领域驱动设计 - 使用ABP框架 - 通用准则
在进入细节之前,让我们看看一些总体的 DDD 原则 数据库提供者 / ORM 无关性 领域和应用程序层应该与 ORM / 数据库提供程序 无关.它们应该只依赖于 Repository 接口,而 Rep ...
- vue封装手机验证码
// 获取验证码 let endMsRes = new Date().getTime() + 45000; localStorage.setItem("myEndTime", JS ...
- Django快速入门之项目配置
开始 环境 python:3.6.2 django:2.0.5 跑起来 用pycharm导入或新建一个Django项目,在目录中存在manage.py的文件,通过下列指令运行Django后台. pyt ...
- 【黑马pink老师的H5/CSS课程】(二)标签与语法
视频链接:P8~P29 黑马程序员pink老师前端入门教程,零基础必看的h5(html5)+css3+移动 参考链接: HTML 元素 1.HTML语法规范 1.1 基本语法概述 HTML 标签是由尖 ...
- bat-配置环境变量
查看环境变量 set 查看当前所有变量 set path 查看变量path的值 echo %xxx% 查看某一个环境变量 临时设置环境变量 set xxx=xxx set xxx= 永久设置环境变量 ...
- 利用IDEA搭建SpringBoot项目,整合mybatis
一.配置文件.启动项目 生成之后这几个文件可以删掉的 配置application spring.datasource.url=jdbc:mysql://localhost:3306/test?serv ...