keys(final String pattern)
{
return redisTemplate.keys(pattern);
}
}
存取Redis数据序列化,作用查看Redis数据时直观,避免乱码显示
package com.demo.springSecurity.redis;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.StringRedisSerializer;
/**
* 存取Redis数据序列化,作用查看Redis数据时直观,避免乱码显示
*/
@Configuration
public class RedisConfig {
@Bean
@SuppressWarnings(value = { "unchecked", "rawtypes" })
public RedisTemplate
设置允许跨域
package com.demo.springSecurity.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class CorsConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
// 设置允许跨域的路径
registry.addMapping("/**")
// 设置允许跨域请求的域名
.allowedOriginPatterns("*")
// 是否允许cookie
.allowCredentials(true)
// 设置允许的请求方式
.allowedMethods("GET", "POST", "DELETE", "PUT")
// 设置允许的header属性
.allowedHeaders("*")
// 跨域允许时间
.maxAge(3600);
}
}
统一返回前端数据类
package com.demo.springSecurity.utils;
import com.fasterxml.jackson.annotation.JsonInclude;
/**
* 统一数据返回
*/
@JsonInclude(JsonInclude.Include.NON_NULL)
public class R {
/**
* 状态码
*/
private Integer code;
/**
* 提示信息,如果有错误时,前端可以获取该字段进行提示
*/
private String msg;
/**
* 查询到的结果数据,
*/
private T data;
public R(Integer code, String msg) {
this.code = code;
this.msg = msg;
}
public R(Integer code, T data) {
this.code = code;
this.data = data;
}
public Integer getCode() {
return code;
}
public void setCode(Integer code) {
this.code = code;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
public R(Integer code, String msg, T data) {
this.code = code;
this.msg = msg;
this.data = data;
}
}
JWT工具类:
package com.demo.springSecurity.utils;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.util.Base64;
import java.util.Date;
import java.util.UUID;
/**
* JWT工具类
*/
public class JwtUtil {
//有效期为
public static final Long JWT_TTL = 60 * 60 *1000L;// 60 * 60 *1000 一个小时
//设置秘钥明文
public static final String JWT_KEY = "yyds";
public static String getUUID(){
String token = UUID.randomUUID().toString().replaceAll("-", "");
return token;
}
/**
* 生成jtw
* @param subject token中要存放的数据(json格式)
* @return
*/
public static String createJWT(String subject) {
JwtBuilder builder = getJwtBuilder(subject, null, getUUID());// 设置过期时间
return builder.compact();
}
/**
* 生成jtw
* @param subject token中要存放的数据(json格式)
* @param ttlMillis token超时时间
* @return
*/
public static String createJWT(String subject, Long ttlMillis) {
JwtBuilder builder = getJwtBuilder(subject, ttlMillis, 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) //唯一的ID
.setSubject(subject) // 主题 可以是JSON数据
.setIssuer("ytt") // 签发者
.setIssuedAt(now) // 签发时间
.signWith(signatureAlgorithm, secretKey) //使用HS256对称加密算法签名, 第二个参数为秘钥
.setExpiration(expDate);
}
/**
* 创建token
* @param id
* @param subject
* @param ttlMillis
* @return
*/
public static String createJWT(String id, String subject, Long ttlMillis) {
JwtBuilder builder = getJwtBuilder(subject, ttlMillis, id);// 设置过期时间
return builder.compact();
}
public static void main(String[] args) throws Exception {
// String jwt = createJWT("2123");
Claims claims = parseJWT("eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiIyOTY2ZGE3NGYyZGM0ZDAxOGU1OWYwNjBkYmZkMjZhMSIsInN1YiI6IjIiLCJpc3MiOiJzZyIsImlhdCI6MTYzOTk2MjU1MCwiZXhwIjoxNjM5OTY2MTUwfQ.NluqZnyJ0gHz-2wBIari2r3XpPp06UMn4JS2sWHILs0");
String subject = claims.getSubject();
System.out.println(subject);
// System.out.println(claims);
}
/**
* 生成加密后的秘钥 secretKey
* @return
*/
public static SecretKey generalKey() {
byte[] encodedKey = Base64.getDecoder().decode(JwtUtil.JWT_KEY);
SecretKey key = new SecretKeySpec(encodedKey, 0, encodedKey.length, "AES");
return key;
}
/**
* 解析
*
* @param jwt
* @return
* @throws Exception
*/
public static Claims parseJWT(String jwt) throws Exception {
SecretKey secretKey = generalKey();
return Jwts.parser()
.setSigningKey(secretKey)
.parseClaimsJws(jwt)
.getBody();
}
}
字符串渲染到客户端WebUtils类:
package com.demo.springSecurity.utils;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class WebUtils
{
/**
* 将字符串渲染到客户端
*
* @param response 渲染对象
* @param string 待渲染的字符串
* @return null
*/
public static String renderString(HttpServletResponse response, String string) {
try
{
response.setStatus(200);
response.setContentType("application/json");
response.setCharacterEncoding("utf-8");
response.getWriter().print(string);
}
catch (IOException e)
{
e.printStackTrace();
}
return null;
}
}
springsecurity相关配置开始:
JwtAuthenticationTokenFilter
package com.demo.springSecurity.security.config;
import com.demo.springSecurity.redis.RedisCache;
import com.demo.springSecurity.sys.entity.LoginUser;
import com.demo.springSecurity.utils.JwtUtil;
import io.jsonwebtoken.Claims;
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;
import java.util.Objects;
@Component
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {
@Autowired
private RedisCache redisCache;
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
//获取token
String token = request.getHeader("token");
if (!StringUtils.hasText(token)) {
//放行
filterChain.doFilter(request, response);
return;
}
//解析token
String userid;
try {
Claims claims = JwtUtil.parseJWT(token);
userid = claims.getSubject();
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException("token非法");
}
//从redis中获取用户信息
String redisKey =userid;
LoginUser loginUser = redisCache.getCacheObject(redisKey);
if(Objects.isNull(loginUser)){
throw new RuntimeException("用户未登录");
}
//存入SecurityContextHolder
//TODO 获取权限信息封装到Authentication中
UsernamePasswordAuthenticationToken authenticationToken =
new UsernamePasswordAuthenticationToken(loginUser,null,loginUser.getAuthorities());
SecurityContextHolder.getContext().setAuthentication(authenticationToken);
//放行
filterChain.doFilter(request, response);
}
}
SecurityConfig
package com.demo.springSecurity.security.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
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.AuthenticationEntryPoint;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter;
@Autowired
private AuthenticationEntryPoint authenticationEntryPoint;
@Autowired
private AccessDeniedHandler accessDeniedHandler;
//创建BCryptPasswordEncoder注入容器
@Bean
public PasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
//关闭csrf
.csrf().disable()
//不通过Session获取SecurityContext
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
// 对于登录接口 允许匿名访问
//knife4j文档放行
.antMatchers("/doc.html", "/swagger-resources/**", "/v2/api-docs", "/v2/api-docs-ext",
"/webjars/**" ).anonymous()
.antMatchers("/user/login").anonymous()
.antMatchers("/reg/userReg").anonymous()
.antMatchers("/test/hello").anonymous()
// .antMatchers("/testCors").hasAuthority("system:dept:list222")
// 除上面外的所有请求全部需要鉴权认证
.anyRequest().authenticated();
//添加过滤器
http.addFilterBefore(jwtAuthenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);
//配置异常处理器
http.exceptionHandling()
//配置认证失败处理器
.authenticationEntryPoint(authenticationEntryPoint)
.accessDeniedHandler(accessDeniedHandler);
//允许跨域
http.cors();
}
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
}
AccessDeniedHandlerImpl
package com.demo.springSecurity.security.handler;
import com.alibaba.fastjson.JSON;
import com.demo.springSecurity.utils.R;
import com.demo.springSecurity.utils.WebUtils;
import org.springframework.http.HttpStatus;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.stereotype.Component;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@Component
public class AccessDeniedHandlerImpl implements AccessDeniedHandler {
@Override
public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {
R result = new R(HttpStatus.FORBIDDEN.value(),"您的权限不足");
String json = JSON.toJSONString(result);
//处理异常
WebUtils.renderString(response,json);
}
}
AuthenticationEntryPointImpl
package com.demo.springSecurity.security.handler;
import com.alibaba.fastjson.JSON;
import com.demo.springSecurity.utils.R;
import com.demo.springSecurity.utils.WebUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.stereotype.Component;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@Component
@Slf4j
public class AuthenticationEntryPointImpl implements AuthenticationEntryPoint {
@Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
R r = new R(HttpStatus.UNAUTHORIZED.value(),"用户认证失败请查询登录");
String json = JSON.toJSONString(r);
//处理异常
WebUtils.renderString(response,json);
log.info("用户认证失败请查询登录");
}
}
SGExpressionRoot
package com.demo.springSecurity.security.handler;
import com.demo.springSecurity.sys.entity.LoginUser;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import java.util.List;
@Component("ex")
public class SGExpressionRoot {
public boolean hasAuthority(String authority){
//获取当前用户的权限
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
LoginUser loginUser = (LoginUser) authentication.getPrincipal();
List permissions = loginUser.getPermissions();
//判断用户权限集合中是否存在authority
return permissions.contains(authority);
}
}
SGFailureHandler
package com.demo.springSecurity.security.handler;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.stereotype.Component;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@Component
@Slf4j
public class SGFailureHandler implements AuthenticationFailureHandler {
@Override
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {
log.info("=================");
System.out.println("认证失败了");
}
}
SGLogoutSuccessHandler
package com.demo.springSecurity.security.handler;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
import org.springframework.stereotype.Component;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@Component
public class SGLogoutSuccessHandler implements LogoutSuccessHandler {
@Override
public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
System.out.println("注销成功");
}
}
SGSuccessHandler
package com.demo.springSecurity.security.handler;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.stereotype.Component;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@Component
public class SGSuccessHandler implements AuthenticationSuccessHandler {
@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
System.out.println("认证成功了");
}
}
业务编写
LoginUser实体类
package com.demo.springSecurity.sys.entity;
import com.alibaba.fastjson.annotation.JSONField;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
@Data
@NoArgsConstructor
public class LoginUser implements UserDetails {
private User user;
private List permissions;
public LoginUser(User user, List permissions) {
this.user = user;
this.permissions = permissions;
}
@JSONField(serialize = false)
private List authorities;
@Override
public Collection getAuthorities() {
if(authorities!=null){
return authorities;
}
//把permissions中String类型的权限信息封装成SimpleGrantedAuthority对象
authorities = new ArrayList<>();
for (String permission : permissions) {
SimpleGrantedAuthority authority = new SimpleGrantedAuthority(permission);
authorities.add(authority);
}
// authorities = permissions.stream()
// .map(SimpleGrantedAuthority::new)
// .collect(Collectors.toList());
return authorities;
}
@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;
}
}
Menu实体类
package com.demo.springSecurity.sys.entity;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonInclude;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
import java.util.Date;
/**
* 菜单表(Menu)实体类
*/
@TableName(value="sys_menu")
@Data
@AllArgsConstructor
@NoArgsConstructor
@JsonInclude(JsonInclude.Include.NON_NULL)
public class Menu implements Serializable {
private static final long serialVersionUID = -54979041104113736L;
@TableId
private Long id;
/**
* 菜单名
*/
private String menuName;
/**
* 路由地址
*/
private String path;
/**
* 组件路径
*/
private String component;
/**
* 菜单状态(0显示 1隐藏)
*/
private String visible;
/**
* 菜单状态(0正常 1停用)
*/
private String status;
/**
* 权限标识
*/
private String perms;
/**
* 菜单图标
*/
private String icon;
private Long createBy;
private Date createTime;
private Long updateBy;
private Date updateTime;
/**
* 是否删除(0未删除 1已删除)
*/
private Integer delFlag;
/**
* 备注
*/
private String remark;
}
SysUserRole权限实体类
package com.demo.springSecurity.sys.entity;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonInclude;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@TableName(value="sys_user_role")
@Data
@AllArgsConstructor
@NoArgsConstructor
@JsonInclude(JsonInclude.Include.NON_NULL)
public class SysUserRole {
// `user_id` bigint NOT NULL AUTO_INCREMENT COMMENT '用户id',
// `role_id` bigint NOT NULL DEFAULT '0' COMMENT '角色id',
private int userId;
private int roleId;
}
User用户数据实体类
package com.demo.springSecurity.sys.entity;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
import java.util.Date;
/**
* 用户表(User)实体类
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
@TableName("sys_user")
public class User implements Serializable {
private static final long serialVersionUID = -40356785423868312L;
/**
* 主键
*/
@TableId
private Long id;
/**
* 用户名
*/
private String userName;
/**
* 昵称
*/
private String nickName;
/**
* 密码
*/
private String password;
/**
* 账号状态(0正常 1停用)
*/
private String status;
/**
* 邮箱
*/
private String email;
/**
* 手机号
*/
private String phonenumber;
/**
* 用户性别(0男,1女,2未知)
*/
private String sex;
/**
* 头像
*/
private String avatar;
/**
* 用户类型(0管理员,1普通用户)
*/
private String userType;
/**
* 创建人的用户id
*/
private Long createBy;
/**
* 创建时间
*/
private Date createTime;
/**
* 更新人
*/
private Long updateBy;
/**
* 更新时间
*/
private Date updateTime;
/**
* 删除标志(0代表未删除,1代表已删除)
*/
private Integer delFlag;
}
MenuMapper层
package com.demo.springSecurity.sys.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.demo.springSecurity.sys.entity.Menu;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
@Mapper
public interface MenuMapper extends BaseMapper
对应的xml文件
UserMapper层
package com.demo.springSecurity.sys.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.demo.springSecurity.sys.entity.User;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface UserMapper extends BaseMapper {
/**
* 根据用户名查询用户数据 该方法用于注册成功添加权限
*/
User findName(String username);
}
对用的xml文件
SysUserRoleMapper层
package com.demo.springSecurity.sys.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.demo.springSecurity.sys.entity.SysUserRole;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.List;
@Mapper
public interface SysUserRoleMapper extends BaseMapper {
}
LoginServcie接口类
package com.demo.springSecurity.sys.service;
import com.demo.springSecurity.utils.R;
public interface LoginServcie {
/**
* 用户登录
* @param
* @return
*/
R login(String username, String password);
/**
* 用户登出 删除Redis与过滤器相关数据
* @return
*/
R logout();
}
LoginServcie实现类
package com.demo.springSecurity.sys.service.Impl;
;
import com.demo.springSecurity.redis.RedisCache;
import com.demo.springSecurity.sys.entity.LoginUser;
import com.demo.springSecurity.sys.service.LoginServcie;
import com.demo.springSecurity.utils.JwtUtil;
import com.demo.springSecurity.utils.R;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
@Service
public class LoginServiceImpl implements LoginServcie {
@Autowired
private AuthenticationManager authenticationManager;
@Autowired
private RedisCache redisCache;
@Autowired
private PasswordEncoder passwordEncoder;
@Override
public R login(String username ,String password) {
//AuthenticationManager authenticate进行用户认证
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(username,password);
Authentication authenticate = authenticationManager.authenticate(authenticationToken);
//如果认证没通过,给出对应的提示
if(Objects.isNull(authenticate)){
throw new RuntimeException("登录失败");
}
//如果认证通过了,使用userid生成一个jwt jwt存入ResponseResult返回
LoginUser loginUser = (LoginUser) authenticate.getPrincipal();
String userid = loginUser.getUser().getId().toString();
String jwt = JwtUtil.createJWT(userid);
Map map = new HashMap<>();
map.put("token",jwt);
//把完整的用户信息存入redis userid作为key
redisCache.setCacheObject(userid,loginUser);
return new R(200,"登录成功",map);
}
@Override
public R logout() {
//获取SecurityContextHolder中的用户id
UsernamePasswordAuthenticationToken authentication = (UsernamePasswordAuthenticationToken) SecurityContextHolder.getContext().getAuthentication();
LoginUser loginUser = (LoginUser) authentication.getPrincipal();
Long userid = loginUser.getUser().getId();
//删除redis中的值
redisCache.deleteObject("login:"+userid);
return new R(200,"注销成功");
}
}
UserDetailsServiceImpl查询用户业务层
package com.demo.springSecurity.sys.service.Impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.demo.springSecurity.sys.entity.LoginUser;
import com.demo.springSecurity.sys.entity.User;
import com.demo.springSecurity.sys.mapper.UserMapper;
import com.demo.springSecurity.sys.mapper.MenuMapper;
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;
import java.util.List;
import java.util.Objects;
@Service
public class UserDetailsServiceImpl implements UserDetailsService {
@Autowired
private UserMapper userMapper;
@Autowired
private MenuMapper menuMapper;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
//查询用户信息
LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(User::getUserName,username);
User user = userMapper.selectOne(queryWrapper);
//如果没有查询到用户就抛出异常
if(Objects.isNull(user)){
throw new RuntimeException("用户名或者密码错误");
}
// List list = new ArrayList<>(Arrays.asList("test","admin"));
List list = menuMapper.selectPermsByUserId(user.getId());
//把数据封装成UserDetails返回
return new LoginUser(user,list);
}
}
登录注册模块
LoginController登录模块
package com.demo.springSecurity.sys.controller;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import com.demo.springSecurity.sys.service.LoginServcie;
import com.demo.springSecurity.utils.R;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
@Api(tags = "登录模块")
@RestController
@RequestMapping("/user")
public class LoginController {
@Autowired
private LoginServcie loginServcie;
/**
* 用户登录
* @param
* @return
*/
@ApiOperationSupport(author = "admin")
@ApiOperation(value = "用户登录")
@PostMapping("/login")
public R login(@RequestParam String username,@RequestParam String password){
//登录
System.out.println("用户登录成功》》》》》》》");
return loginServcie.login(username,password);
}
/**
* 用户登出 同时删除Redis缓存的token
* @return
*/
@ApiOperationSupport(author = "admin")
@ApiOperation(value = "用户登出注销token")
@GetMapping("/logout")
public R logout(){
return loginServcie.logout();
}
}
RegController注册模块
package com.demo.springSecurity.sys.controller;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import com.demo.springSecurity.sys.entity.SysUserRole;
import com.demo.springSecurity.sys.entity.User;
import com.demo.springSecurity.sys.mapper.MenuMapper;
import com.demo.springSecurity.sys.mapper.SysUserRoleMapper;
import com.demo.springSecurity.sys.mapper.UserMapper;
import com.demo.springSecurity.utils.R;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.Date;
@Api(tags = "注册模块")
@RestController
@RequestMapping("/reg")
public class RegController {
@Autowired
private UserMapper userMapper;
@Autowired
private PasswordEncoder passwordEncoder;
@Autowired
private MenuMapper menuMapper;
@Autowired
private SysUserRoleMapper sysUserRoleMapper;
@ApiOperationSupport(author = "admin")
@ApiOperation(value = "用户注册")
@PostMapping("/userReg")
public R reg(@RequestParam String username,@RequestParam String password){
if (username==null || password==null){
return new R(500,"用户名或者密码不能为空");
}
LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>();
wrapper.eq(User::getUserName,username);
User user = userMapper.selectOne(wrapper);
if (user!=null){
return new R(500,"该用户已经存在");
}
String encode = passwordEncoder.encode(password);
User u = new User();
u.setUserName(username);
u.setPassword(encode);
u.setNickName("普通用户");
u.setStatus("0");
u.setDelFlag(0);
u.setCreateTime(new Date());
u.setUpdateTime(new Date());
int insert = userMapper.insert(u);
if (insert!=1){
return new R(500,"注册失败");
}
User listName = userMapper.findName(username);
if (listName!=null){
Long id = listName.getId();
SysUserRole sysUserRole = new SysUserRole();
sysUserRole.setUserId(Math.toIntExact(id));
sysUserRole.setRoleId(444); //员工默认权限为普通员工
int insert1 = sysUserRoleMapper.insert(sysUserRoleMapper);
if (insert1==1){
System.out.println("添加权限成功");
}else {
System.out.println("添加权限失败");
}
}
return new R(200,"注册成功");
}
}
TestController权限测试模块
package com.demo.springSecurity.sys.controller;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import com.demo.springSecurity.utils.R;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@Api(tags = "权限认证测试")
@RestController
@RequestMapping("/oxx")
public class TestController {
@ApiOperationSupport(author = "admin")
@ApiOperation(value = "oaa权限接口才能访问")
@GetMapping("/hello")
@PreAuthorize("@ex.hasAuthority('oaa')")
// @PreAuthorize("hasAnyAuthority('admin','test','system:dept:list')")
// @PreAuthorize("hasRole('oaa')")
// @PreAuthorize("hasAnyRole('admin','system:dept:list')")
public String hello(){
return "访问成功";
}
@ApiOperationSupport(author = "admin")
@ApiOperation(value = "oaa以下权限可以访问")
@PreAuthorize("@ex.hasAuthority('obb')")
@GetMapping("/testCors")
public R testCors(){
return new R(200,"访问成功");
}
}
项目整体结构

测试项目:http://localhost:8888/doc.html

第一步:登录获取token

第二步:配置全局token

第三步:开始测试权限
有权限

无权限的情况就换一个权限低的账号(李四 123)
项目Gitee地址
SpringSecurity: 基于SpringSecurity实现的一款权限认证系统
你可能感兴趣的:(spring,boot,java,后端)
- java 第十章 线程(1)
点纭
java开发语言网络
目录认识线程程序进程线程特点·:创建线程继承Thread类的方法实现Runnable接口的方法Tread类中的方法线程状态认识线程程序进程线程程序(program):是为完成特定任务,用某种语言编写的一组指令的集合。即指一段静态的代码。进程(process)正在内存中运行的应用程序,如运行中的QQ,运行中的音乐播放器。进程是操作系统进行资源分配的最小单位.线程(thread)进程可进一步细化为线程
- 【数据结构】二叉树的特性
多多钟意你吖
阶段一:数据结构数据结构二叉树二叉树的特性
作者简介:大家好呀!我是路遥叶子,大家可以叫我叶子哦!❣️个人主页:【路遥叶子的博客】博主信息:四季轮换叶,一路招摇胜!专栏【安利Java零基础】【数据结构-Java语言描述】希望大家多多支持一起进步呀!~❤️若有帮助,还请【关注➕点赞➕收藏】,不行的话我再努力努力呀!————————————————⚡版权声明:本文由【路遥叶子】原创、在CSDN首发、需要转载请联系博主。想寻找共同成长的小伙伴,请
- Spring基础知识——笔记整理(一)
豆萌萌 网课大咖
笔记整理springjava
Spring简介Spring是一个轻量级Java开发框架,由RodJohnson创建,目的是为了解决企业级应用开发的业务逻辑层和其他各层的耦合问题。它是一个JavaSE/JavaEE分层的full-stack(一站式)轻量级开源框架,为开发Java应用程序提供全面的基础架构支持。Spring负责基础架构,因此Java开发者可以专注于应用程序的开发。Spring的优点方便解耦,简化开发:Spring
- 平均数1(acwing)c/c++/java/python
xinghuitunan
c++c语言javapython
读取两个浮点数AA和BB的值,对应于两个学生的成绩。请你计算学生的平均分,其中AA的成绩的权重为3.53.5,BB的成绩的权重为7.57.5。成绩的取值范围在00到1010之间,且均保留一位小数。输入格式输入占两行,每行包含一个浮点数,第一行表示AA,第二行表示BB。输出格式输出格式为MEDIA=X,其中XX为平均分,结果保留五位小数。数据范围0≤A,B≤10.00≤A,B≤10.0输入样例:5.
- Github 2024-06-10开源项目周报 Top15
老孙正经胡说
github开源Github趋势分析开源项目PythonGolang
根据GithubTrendings的统计,本周(2024-06-10统计)共有15个项目上榜。根据开发语言中项目的数量,汇总情况如下:开发语言项目数量Python项目8JupyterNotebook项目2Go项目2C++项目1Shell项目1Lua项目1JavaScript项目1MDX项目1C项目1HTML项目1Python-100天从新手到大师创建周期:2234天开发语言:Python,HTML
- spring生命周期流程图
xaqw
笔记
Spring作为当前Java最流行、最强大的轻量级框架,受到了程序员的热烈欢迎。准确的了解SpringBean的生命周期是非常必要的。我们通常使用ApplicationContext作为Spring容器。这里,我们讲的也是ApplicationContext中Bean的生命周期。而实际上BeanFactory也是差不多的,只不过处理器需要手动注册。转载请注明地址http://www.cnblogs
- 开源项目-图书管理系统
代码先觉
开源项目java图书管理系统
哈喽,大家好,今天给大家带来一个图书管理系统系统主要分为图书管理,读者管理,借还管理等模块,可以下载源码了解详情项目简介本图书管理系统基于spring,springmvc,数据库为mysql。前端使用了Bootstrap。系统功能该系统实现读者和管理员登陆,图书的增删改查,读者的增删改查,借还图书,密码修改,卡号挂失,超期提醒等功能。系统登录图书管理读者管理
- RocketMQ(3)-SpringBoot集成简单测试
gzh-程序员灿灿
中间件消息队列
测试RocketMQ服务可用性我这里把provider和consumer放到同一个项目中,进行简单测试。后续写个RocketMQ的包装包。文章目录测试RocketMQ服务可用性providerconsumerconsumer监听消费testRocketMQ组的概念RocketMQ分组使用场景rocketmq的重试注意:项目中引用的rocketmq客户端,其版本需要和服务端安装的mq的版本保持一致,
- Java数据结构与算法(买卖股票的最佳时机二贪心算法)
盘门
java数据结构与算法实战java开发语言
前言买卖股票最佳时机二,此时不限次数的买卖的要求获得的利益最大化。暴力算法依旧可行,可以参考之前的练习。.-力扣(LeetCode)贪心算法原理参考:Java数据结构与算法(盛水的容器贪心算法)-CSDN博客实现原理1.定义最大利润res和下标前值pre。2.下标移动比较当前股票值prices[i]与前值大小,前值小于当前值则加入利润res。3.随着下标移动前值更新。具体代码实现classSolu
- 解决 前端 number 与后端 Long 数据表示范围不精确的问题
confident3
前端
packagecom.me.meterdemo.config;importcom.fasterxml.jackson.databind.ObjectMapper;importcom.fasterxml.jackson.databind.module.SimpleModule;importcom.fasterxml.jackson.databind.ser.std.ToStringSerialize
- webpack和vite区别
雅望天堂i
javascript前端
1.工作原理WebpackWebpack是一个静态模块打包工具。它会从入口文件开始,递归地分析项目中的所有依赖,构建出一个依赖图。然后,它会根据配置中的规则,使用不同的loader对各种类型的文件(如JS、CSS、图片等)进行处理和转换,最后将所有模块打包成一个或多个静态资源文件。例如,当项目中有一个JavaScript文件引入了CSS文件和图片,Webpack会先使用CSSloader处理CSS
- Java高级之动态代理
java
Java高级之动态代理动态代理的实现1.创建接口2.创建被代理类,需要重写接口类3.创建代理类和代理类对象测试Java动态代理是Java反射机制的一种应用,它可以在运行时动态生成代理类,实现对原对象的代理。Java动态代理主要利用java.lang.reflect包中的Proxy类和InvocationHandler接口来实现。通过这种方式,我们可以为对象添加额外的行为,而无需修改其源代码。动态代
- java菜鸟教程学习(完整版)
javapython
java实例一.Java字符串1.Java实例–字符串比较2.Java实例-查找字符串最后一次出现的位置3.Java实例-删除字符串中的一个字符4.Java实例-字符串替换5.Java实例-字符串反转6.Java实例-字符串查找7.Java实例-字符串分割8.Java实例-字符串分割(StringTokenizer)9.Java实例-字符串小写转大写10.Java实例-测试两个字符串区域是否相等1
- 前端面试常见手写代码题
前端面试
文章目录前言:防抖节流函数柯里化函数组合instanceof实现实现new操作符的行为深拷贝继承实现:手写Promise数组中常见函数的实现前言:在前端面试中,经常会遇到要求手写的代码的题目,主要是考察我们的编程能力、和对JavaScript的理解以及对前端最佳实践的掌握。下面是我整理了一些常见的手写代码题目,您可以看看自己能实现哪些。。防抖防抖函数,确保一段时间内多次触发事件只执行一次。//--
- Github 2025-02-17 开源项目周报Top15
老孙正经胡说
github开源Github趋势分析开源项目PythonGolang
根据GithubTrendings的统计,本周(2025-02-17统计)共有15个项目上榜。根据开发语言中项目的数量,汇总情况如下:开发语言项目数量Python项目7TypeScript项目6JupyterNotebook项目2JavaScript项目1文档项目1PHP项目1从零开始构建你喜爱的技术创建周期:2156天Star数量:253338个Fork数量:24043次关注人数:253338人
- Spring 核心技术解析【纯干货版】- XI:Spring 数据访问模块 Spring-Oxm 模块精讲
栗筝i
栗筝i的Java技术栈#Java框架-专栏springpython数据库
在现代Java开发中,XML仍然是数据存储和数据交换的重要格式,特别是在Web服务、配置管理和数据持久化等场景中。Spring框架提供了Spring-OXM(Object/XMLMapping)模块,旨在简化Java对象与XML之间的转换,并支持多种OXM实现,如JAXB、Castor、XStream、JibX等。本篇文章深入解析了Spring-OXM模块的核心概念,并结合JAXB进行详细示例,展
- 将RocketMQ集成到了Spring Boot项目中,实现站内信功能
liangblog
全栈开发Java并发java-rocketmqrocketmqspringboot
1.添加依赖首先,在pom.xml中添加RocketMQ的依赖:org.springframework.bootspring-boot-starter-weborg.springframework.bootspring-boot-starter-data-jpacom.h2databaseh2runtimeorg.springframework.bootspring-boot-starter-da
- Spring Boot项目中使用MyBatis
wujiada001
Javaspringbootmybatis后端
在SpringBoot项目中使用MyBatis可以极大地简化配置过程,因为SpringBoot提供了很多自动化配置的功能。以下是一个简单的指南,介绍如何在SpringBoot项目中使用MyBatis。1.添加依赖首先,你需要在pom.xml文件中添加MyBatis和MyBatis-Spring-Boot-Starter的依赖。MyBatis-Spring-Boot-Starter是MyBatis官
- Spring Bean的作用域详解:掌控对象的创建与生命周期
从不吃红薯
springjava后端
引言在Spring框架中,Bean的作用域(Scope)决定了对象在IOC容器中的创建方式、生命周期及共享范围。正确配置作用域是优化应用性能、管理资源的关键。本文将深入解析SpringBean的常见作用域,并通过代码示例演示如何配置和验证其行为。Bean作用域的核心类型Spring支持多种作用域,最常用的两种是:作用域含义对象创建时机适用场景singleton默认作用域,整个IOC容器中仅存在一个
- 写出一个简单的JavaScript闭包示例,并解释为什么它形成了闭包。
IT木昜
大白话前端面试题javascript开发语言ecmascript
写出一个简单的JavaScript闭包示例,并解释为什么它形成了闭包。闭包示例代码functionouterFunction(){//定义一个变量,该变量处于outerFunction的作用域内letmessage='这是一个闭包示例';//定义一个内部函数innerFunctionfunctioninnerFunction(){//内部函数可以访问外部函数作用域中的变量messageconsol
- Java vs C++:2025年编程语言之争——谁将主宰未来?
爱吃青菜的大力水手
javac++开发语言
在编程的世界里,Java和C++是两门经久不衰的语言,各自凭借独特的优势吸引了大量IT工作者的关注。无论是企业级开发还是高性能系统编程,这两门语言都在各自的领域中扮演着重要角色。本文深入调研并对比Java和C++在市场份额、插件丰富度、学习成本、安全性等方面的表现,帮助您理解它们的优势与应用场景,并在选择编程语言时做出明智决策。1.市场份额与流行度根据TIOBE指数(2024年最新数据),Java
- Springboot Maven打包跳过测试的五种方式总结 -Dmaven.test.skip=true
泡泡Java
面试学习路线阿里巴巴springbootmaven后端
使用Maven打包的时候,可能会因为单元测试打包失败,这时候就需要跳过单元测试。也为了加快打包速度,也需要跳过单元测试。Maven跳过单元测试五种方法。在正式环境中运行Springboot应用,需要先打包,然后使用java-jarxx.jar就能运行我们的项目。我们平时使用的在开发中使用的是开发或测试的数据库,和生产上面的一般是隔离的,意味着打包的时候需要激活生产的配置文件,但是我们不一定有访问生
- 函数调用和 Java 与 Spring AI 模型的集成
算法资料吧!
javaspring人工智能
SpringAI是一个功能强大的SpringFramework项目,它为Java开发人员带来了人工智能(AI)功能。通过将AI模型集成到Java应用程序中,SpringAI简化了创建智能应用程序的过程,同时利用了Spring生态系统的稳健性。本文将指导您完成使用SpringAI将AI模型集成到Java应用程序中的步骤,特别关注允许AI模型与外部数据源和服务动态交互的函数调用机制。SpringAIS
- Java Web开发:从入门到实战的技术之旅
计算机学长
java开发工具开发语言java
一、JavaWeb开发初印象在互联网技术飞速发展的当下,JavaWeb开发已成为构建各类网络应用的中流砥柱。简单来说,JavaWeb开发就是利用Java语言及其相关技术,开发出能够在Web服务器上运行,并通过浏览器等客户端进行访问的应用程序。这些应用程序可以是功能丰富的网站、交互性强的Web应用,也可以是复杂的企业级信息系统,广泛应用于电商、金融、教育、医疗等各个领域。当我们在淘宝上尽情购物、在支
- Java-Mybatis-Spring配置详解
csdn_yasin
JavaSpringjavaspringMybatisMybatis-Spring
概念什么是MyBatis-Spring?MyBatis-Spring会帮助你将MyBatis代码无缝地整合到Spring中。它将允许MyBatis参与到Spring的事务管理之中,创建映射器mapper和SqlSession并注入到bean中,以及将Mybatis的异常转换为Spring的DataAccessException。最终,可以做到应用代码不依赖于MyBatis,Spring或MyBat
- Spring整合Mybatis(配置类实现)
小王就爱报错
springmybatisjava
一、引入所需依赖org.springframeworkspring-context5.3.31org.mybatismybatis3.5.15org.mybatismybatis-spring2.0.7org.springframeworkspring-jdbc5.1.9.RELEASEmysqlmysql-connector-java8.0.33junitjunit4.13.2testcom.a
- Java Stream API
曾续缘
java大数据
“【曾续缘聊技术】专栏持续更新中!我是深耕计算机领域的曾续缘,专注用通俗语言讲透硬核知识。关注+星标,获取最新技术干货推送!”JavaStreamAPI是Java8中引入的一个强大特性,它提供了一种高效且易于理解的数据处理方式。在处理集合时,StreamAPI允许我们以声明式的方式表达复杂的数据处理操作,从而简化代码并提高效率。JavaStreamAPI基础创建Stream通过集合:任何集合都可以
- 华为OD机试真题-相对开音节-OD统一考试(E卷)
ai因思坦
华为OD机试2024真题题库华为od面试开发语言算法
最新华为OD机试考点合集:华为OD机试2024年真题题库(E卷+D卷+C卷)_华为od机试题库-CSDN博客每一题都含有详细的解题思路和代码注释,精编c++、JAVA、Python三种语言解法。帮助每一位考生轻松、高效刷题。订阅后永久可看,发现新题及时跟新。题目描述相对开音节构成的结构为:辅音+元音(aeiou)+辅音(r除外)+e。常见
- 士大夫身份第三方水电费第三方
moqiyong666
springjava后端
packagecom.snmocha.snbpm.job;importorg.springframework.stereotype.Component;importcom.xxl.job.core.handler.annotation.XxlJob;importlombok.extern.slf4j.Slf4j;/***Demo定时任务.*Author:zhoudd*Date:2023-01-15
- 包含32英文特殊字符,正则表达式验证
moqiyong666
正则表达式
//JavaStringpattern=".*[~!@#$%^&*()_+|\?\`\-\=\[\]\\;\'\,\.\/])/;alert(pattern.test("~"));
- Java 并发包之线程池和原子计数
lijingyao8206
Java计数ThreadPool并发包java线程池
对于大数据量关联的业务处理逻辑,比较直接的想法就是用JDK提供的并发包去解决多线程情况下的业务数据处理。线程池可以提供很好的管理线程的方式,并且可以提高线程利用率,并发包中的原子计数在多线程的情况下可以让我们避免去写一些同步代码。
这里就先把jdk并发包中的线程池处理器ThreadPoolExecutor 以原子计数类AomicInteger 和倒数计时锁C
- java编程思想 抽象类和接口
百合不是茶
java抽象类接口
接口c++对接口和内部类只有简介的支持,但在java中有队这些类的直接支持
1 ,抽象类 : 如果一个类包含一个或多个抽象方法,该类必须限定为抽象类(否者编译器报错)
抽象方法 : 在方法中仅有声明而没有方法体
package com.wj.Interface;
- [房地产与大数据]房地产数据挖掘系统
comsci
数据挖掘
随着一个关键核心技术的突破,我们已经是独立自主的开发某些先进模块,但是要完全实现,还需要一定的时间...
所以,除了代码工作以外,我们还需要关心一下非技术领域的事件..比如说房地产
&nb
- 数组队列总结
沐刃青蛟
数组队列
数组队列是一种大小可以改变,类型没有定死的类似数组的工具。不过与数组相比,它更具有灵活性。因为它不但不用担心越界问题,而且因为泛型(类似c++中模板的东西)的存在而支持各种类型。
以下是数组队列的功能实现代码:
import List.Student;
public class
- Oracle存储过程无法编译的解决方法
IT独行者
oracle存储过程
今天同事修改Oracle存储过程又导致2个过程无法被编译,流程规范上的东西,Dave 这里不多说,看看怎么解决问题。
1. 查看无效对象
XEZF@xezf(qs-xezf-db1)> select object_name,object_type,status from all_objects where status='IN
- 重装系统之后oracle恢复
文强chu
oracle
前几天正在使用电脑,没有暂停oracle的各种服务。
突然win8.1系统奔溃,无法修复,开机时系统 提示正在搜集错误信息,然后再开机,再提示的无限循环中。
无耐我拿出系统u盘 准备重装系统,没想到竟然无法从u盘引导成功。
晚上到外面早了一家修电脑店,让人家给装了个系统,并且那哥们在我没反应过来的时候,
直接把我的c盘给格式化了 并且清理了注册表,再装系统。
然后的结果就是我的oracl
- python学习二( 一些基础语法)
小桔子
pthon基础语法
紧接着把!昨天没看继续看django 官方教程,学了下python的基本语法 与c类语言还是有些小差别:
1.ptyhon的源文件以UTF-8编码格式
2.
/ 除 结果浮点型
// 除 结果整形
% 除 取余数
* 乘
** 乘方 eg 5**2 结果是5的2次方25
_&
- svn 常用命令
aichenglong
SVN版本回退
1 svn回退版本
1)在window中选择log,根据想要回退的内容,选择revert this version或revert chanages from this version
两者的区别:
revert this version:表示回退到当前版本(该版本后的版本全部作废)
revert chanages from this versio
- 某小公司面试归来
alafqq
面试
先填单子,还要写笔试题,我以时间为急,拒绝了它。。时间宝贵。
老拿这些对付毕业生的东东来吓唬我。。
面试官很刁难,问了几个问题,记录下;
1,包的范围。。。public,private,protect. --悲剧了
2,hashcode方法和equals方法的区别。谁覆盖谁.结果,他说我说反了。
3,最恶心的一道题,抽象类继承抽象类吗?(察,一般它都是被继承的啊)
4,stru
- 动态数组的存储速度比较 集合框架
百合不是茶
集合框架
集合框架:
自定义数据结构(增删改查等)
package 数组;
/**
* 创建动态数组
* @author 百合
*
*/
public class ArrayDemo{
//定义一个数组来存放数据
String[] src = new String[0];
/**
* 增加元素加入容器
* @param s要加入容器
- 用JS实现一个JS对象,对象里有两个属性一个方法
bijian1013
js对象
<html>
<head>
</head>
<body>
用js代码实现一个js对象,对象里有两个属性,一个方法
</body>
<script>
var obj={a:'1234567',b:'bbbbbbbbbb',c:function(x){
- 探索JUnit4扩展:使用Rule
bijian1013
java单元测试JUnitRule
在上一篇文章中,讨论了使用Runner扩展JUnit4的方式,即直接修改Test Runner的实现(BlockJUnit4ClassRunner)。但这种方法显然不便于灵活地添加或删除扩展功能。下面将使用JUnit4.7才开始引入的扩展方式——Rule来实现相同的扩展功能。
1. Rule
&n
- [Gson一]非泛型POJO对象的反序列化
bit1129
POJO
当要将JSON数据串反序列化自身为非泛型的POJO时,使用Gson.fromJson(String, Class)方法。自身为非泛型的POJO的包括两种:
1. POJO对象不包含任何泛型的字段
2. POJO对象包含泛型字段,例如泛型集合或者泛型类
Data类 a.不是泛型类, b.Data中的集合List和Map都是泛型的 c.Data中不包含其它的POJO
- 【Kakfa五】Kafka Producer和Consumer基本使用
bit1129
kafka
0.Kafka服务器的配置
一个Broker,
一个Topic
Topic中只有一个Partition() 1. Producer:
package kafka.examples.producers;
import kafka.producer.KeyedMessage;
import kafka.javaapi.producer.Producer;
impor
- lsyncd实时同步搭建指南——取代rsync+inotify
ronin47
1. 几大实时同步工具比较 1.1 inotify + rsync
最近一直在寻求生产服务服务器上的同步替代方案,原先使用的是 inotify + rsync,但随着文件数量的增大到100W+,目录下的文件列表就达20M,在网络状况不佳或者限速的情况下,变更的文件可能10来个才几M,却因此要发送的文件列表就达20M,严重减低的带宽的使用效率以及同步效率;更为要紧的是,加入inotify
- java-9. 判断整数序列是不是二元查找树的后序遍历结果
bylijinnan
java
public class IsBinTreePostTraverse{
static boolean isBSTPostOrder(int[] a){
if(a==null){
return false;
}
/*1.只有一个结点时,肯定是查找树
*2.只有两个结点时,肯定是查找树。例如{5,6}对应的BST是 6 {6,5}对应的BST是
- MySQL的sum函数返回的类型
bylijinnan
javaspringsqlmysqljdbc
今天项目切换数据库时,出错
访问数据库的代码大概是这样:
String sql = "select sum(number) as sumNumberOfOneDay from tableName";
List<Map> rows = getJdbcTemplate().queryForList(sql);
for (Map row : rows
- java设计模式之单例模式
chicony
java设计模式
在阎宏博士的《JAVA与模式》一书中开头是这样描述单例模式的:
作为对象的创建模式,单例模式确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例。这个类称为单例类。 单例模式的结构
单例模式的特点:
单例类只能有一个实例。
单例类必须自己创建自己的唯一实例。
单例类必须给所有其他对象提供这一实例。
饿汉式单例类
publ
- javascript取当月最后一天
ctrain
JavaScript
<!--javascript取当月最后一天-->
<script language=javascript>
var current = new Date();
var year = current.getYear();
var month = current.getMonth();
showMonthLastDay(year, mont
- linux tune2fs命令详解
daizj
linuxtune2fs查看系统文件块信息
一.简介:
tune2fs是调整和查看ext2/ext3文件系统的文件系统参数,Windows下面如果出现意外断电死机情况,下次开机一般都会出现系统自检。Linux系统下面也有文件系统自检,而且是可以通过tune2fs命令,自行定义自检周期及方式。
二.用法:
Usage: tune2fs [-c max_mounts_count] [-e errors_behavior] [-g grou
- 做有中国特色的程序员
dcj3sjt126com
程序员
从出版业说起 网络作品排到靠前的,都不会太难看,一般人不爱看某部作品也是因为不喜欢这个类型,而此人也不会全不喜欢这些网络作品。究其原因,是因为网络作品都是让人先白看的,看的好了才出了头。而纸质作品就不一定了,排行榜靠前的,有好作品,也有垃圾。 许多大牛都是写了博客,后来出了书。这些书也都不次,可能有人让为不好,是因为技术书不像小说,小说在读故事,技术书是在学知识或温习知识,有
- Android:TextView属性大全
dcj3sjt126com
textview
android:autoLink 设置是否当文本为URL链接/email/电话号码/map时,文本显示为可点击的链接。可选值(none/web/email/phone/map/all) android:autoText 如果设置,将自动执行输入值的拼写纠正。此处无效果,在显示输入法并输
- tomcat虚拟目录安装及其配置
eksliang
tomcat配置说明tomca部署web应用tomcat虚拟目录安装
转载请出自出处:http://eksliang.iteye.com/blog/2097184
1.-------------------------------------------tomcat 目录结构
config:存放tomcat的配置文件
temp :存放tomcat跑起来后存放临时文件用的
work : 当第一次访问应用中的jsp
- 浅谈:APP有哪些常被黑客利用的安全漏洞
gg163
APP
首先,说到APP的安全漏洞,身为程序猿的大家应该不陌生;如果抛开安卓自身开源的问题的话,其主要产生的原因就是开发过程中疏忽或者代码不严谨引起的。但这些责任也不能怪在程序猿头上,有时会因为BOSS时间催得紧等很多可观原因。由国内移动应用安全检测团队爱内测(ineice.com)的CTO给我们浅谈关于Android 系统的开源设计以及生态环境。
1. 应用反编译漏洞:APK 包非常容易被反编译成可读
- C#根据网址生成静态页面
hvt
Web.netC#asp.nethovertree
HoverTree开源项目中HoverTreeWeb.HVTPanel的Index.aspx文件是后台管理的首页。包含生成留言板首页,以及显示用户名,退出等功能。根据网址生成页面的方法:
bool CreateHtmlFile(string url, string path)
{
//http://keleyi.com/a/bjae/3d10wfax.htm
stri
- SVG 教程 (一)
天梯梦
svg
SVG 简介
SVG 是使用 XML 来描述二维图形和绘图程序的语言。 学习之前应具备的基础知识:
继续学习之前,你应该对以下内容有基本的了解:
HTML
XML 基础
如果希望首先学习这些内容,请在本站的首页选择相应的教程。 什么是SVG?
SVG 指可伸缩矢量图形 (Scalable Vector Graphics)
SVG 用来定义用于网络的基于矢量
- 一个简单的java栈
luyulong
java数据结构栈
public class MyStack {
private long[] arr;
private int top;
public MyStack() {
arr = new long[10];
top = -1;
}
public MyStack(int maxsize) {
arr = new long[maxsize];
top
- 基础数据结构和算法八:Binary search
sunwinner
AlgorithmBinary search
Binary search needs an ordered array so that it can use array indexing to dramatically reduce the number of compares required for each search, using the classic and venerable binary search algori
- 12个C语言面试题,涉及指针、进程、运算、结构体、函数、内存,看看你能做出几个!
刘星宇
c面试
12个C语言面试题,涉及指针、进程、运算、结构体、函数、内存,看看你能做出几个!
1.gets()函数
问:请找出下面代码里的问题:
#include<stdio.h>
int main(void)
{
char buff[10];
memset(buff,0,sizeof(buff));
- ITeye 7月技术图书有奖试读获奖名单公布
ITeye管理员
活动ITeye试读
ITeye携手人民邮电出版社图灵教育共同举办的7月技术图书有奖试读活动已圆满结束,非常感谢广大用户对本次活动的关注与参与。
7月试读活动回顾:
http://webmaster.iteye.com/blog/2092746
本次技术图书试读活动的优秀奖获奖名单及相应作品如下(优秀文章有很多,但名额有限,没获奖并不代表不优秀):
《Java性能优化权威指南》