临时接了一个小项目,有需要搭一个小项目,简单记录一下项目搭建过程以及整合登录功能。

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登录的更多相关文章

  1. SpringBoot 项目搭建(详细介绍+案例源码)

    SpringBoot 项目搭建 SpringBoot 项目整合源码 SpringBoot 项目整合 一.项目准备 1.1 快速创建 SpringBoot 项目 1.2 标准项目结构图如下 1.3 添加 ...

  2. SpringBoot之入门教程-SpringBoot项目搭建

    SpringBoot大大的简化了Spring的配置,把Spring从配置炼狱中解救出来了,以前天天配置Spring和Mybatis,Springmvc,Hibernate等整合在一起,感觉用起来还是挺 ...

  3. SpringBoot项目搭建与打包

    一.环境准备 本地java环境jdk1.8 Maven版本3.5.2 IDE工具idea2017 二.SpringBoot微服务搭建 1.点击File >> New >> Pr ...

  4. springboot系列二、springboot项目搭建

    一.官网快速构建 1.maven构建项目 1.访问http://start.spring.io/ 2.选择构建工具Maven Project.Spring Boot版本2.1.1以及一些工程基本信息, ...

  5. 从零开始的SpringBoot项目搭建

    前言 今天是我加入博客园的第一天今天刚好学习到SpringBoot,就顺便记录一下吧 一.创建项目 1.创建工程 ① 通过File > New > Project,新建工程,选择Sprin ...

  6. Springboot项目搭建(3)-shiro登录

    shiro简述+实现简单登录:https://www.jianshu.com/p/7f724bec3dc3

  7. springboot项目搭建及常用技术整合

    一.在你建立的工程下创建 Module 选择Spring initializr创建. 二.在Type处选择: Maven Project(项目的构建工具) 三.创建依赖时勾上web,mybatis,m ...

  8. oa_mvc_easyui_项目搭建及登录页面验证码(1)

    1.空项目的搭建,三层的搭建(各层之中的引用) webapp:bll,model,common bll:dal,model dal:model 2.SQL表 ItcastDb:T_UserInfo,T ...

  9. springboot项目搭建:结构和入门程序

    Spring Boot 推荐目录结构 代码层的结构 根目录:com.springboot 1.工程启动类(ApplicationServer.java)置于com.springboot.build包下 ...

随机推荐

  1. CVPR2022 | 重新审视池化:你的感受野不是最理想的

    前言 本文提出了一种简单而有效的动态优化池操作( Dynamically Optimized Pooling operation),称为DynOPool,它通过学习每一层感受野的最佳大小和形状来优化特 ...

  2. DirectX11 With Windows SDK--19(Dev) 编译Assimp并加载模型、新的Effects框架

    前言 注意:这一章进行了重写,对应教程Dev分支第19章的项目,在更新完后面的项目后会替换掉原来第19章的教程 在前面的章节中我们一直使用的是由代码生成的几何模型,但现在我们希望能够导入模型设计师生成 ...

  3. Eclipse For Java开发环境部署

    Eclipse For Java开发环境部署 1.准备工作 jdk安装包 jdk官网下载 Eclipse安装包 Eclipse官网下载 Eclipse下载时选择图中所示的国内镜像地址下载 下载后的文件 ...

  4. 智慧机房3D可视化技术解决方案

    随着夏季气温越来越高,机房内大量设备同步工作时,难免使机房内温度飙升. 机房温度每升高10℃,计算机的可靠性就下降25% 磁盘磁带也会因热涨效应造成记录错误 计算机的时钟主频在温度过高都会降低 UPS ...

  5. 实现领域驱动设计 - 使用ABP框架 - 通用准则

    在进入细节之前,让我们看看一些总体的 DDD 原则 数据库提供者 / ORM 无关性 领域和应用程序层应该与 ORM / 数据库提供程序 无关.它们应该只依赖于 Repository 接口,而 Rep ...

  6. vue封装手机验证码

    // 获取验证码 let endMsRes = new Date().getTime() + 45000; localStorage.setItem("myEndTime", JS ...

  7. Django快速入门之项目配置

    开始 环境 python:3.6.2 django:2.0.5 跑起来 用pycharm导入或新建一个Django项目,在目录中存在manage.py的文件,通过下列指令运行Django后台. pyt ...

  8. 【黑马pink老师的H5/CSS课程】(二)标签与语法

    视频链接:P8~P29 黑马程序员pink老师前端入门教程,零基础必看的h5(html5)+css3+移动 参考链接: HTML 元素 1.HTML语法规范 1.1 基本语法概述 HTML 标签是由尖 ...

  9. bat-配置环境变量

    查看环境变量 set 查看当前所有变量 set path 查看变量path的值 echo %xxx% 查看某一个环境变量 临时设置环境变量 set xxx=xxx set xxx= 永久设置环境变量 ...

  10. 利用IDEA搭建SpringBoot项目,整合mybatis

    一.配置文件.启动项目 生成之后这几个文件可以删掉的 配置application spring.datasource.url=jdbc:mysql://localhost:3306/test?serv ...