springboot
Can be said now do javaweb
to develop the hottest technology, I based springboot
process to build a project, stepped on a lot of the pit, we found not only the integration framework introduced starter
so simple.
To be simple, easy to use, more scalable, need to do a lot of secondary packaging, so they wrote based springboot
web projects of scaffolding, for some common integration framework, and a simple secondary package.
Project name baymax
is taken from the cartoon super marines inside the white, white is a medical inflatable robot, hope you like this project to light as dear, you can reduce your workload.
github https://github.com/zhaoguhong/baymax
web
web module is essential for a project to develop web module
maven dependence
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
For the separation of front and rear ends, recommendations directly @RestController
annotations
should be noted that, not recommended to directly use RequstMapping annotation type and does not specify the method of writing , recommended GetMaping
or PostMaping
annotation like
@SpringBootApplication
@RestController
public class BaymaxApplication {
public static void main(String[] args) {
SpringApplication.run(BaymaxApplication.class, args);
}
@GetMapping("/test")
public String test() {
return "hello baymax";
}
}
unit test
spring unit testing also provides good support
maven dependence
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
Adding @RunWith(SpringRunner.class)
and @SpringBootTest
can be tested
@RunWith(SpringRunner.class)
@SpringBootTest
public class WebTest {
}
For Controller
the interface layer, it can be directly used MockMvc
for testing
@RunWith(SpringRunner.class)
@SpringBootTest
public class WebTest {
@Autowired
private WebApplicationContext context;
private MockMvc mvc;
@Before
public void setUp() throws Exception {
mvc = MockMvcBuilders.webAppContextSetup(context).build();
}
@Test
public void testValidation() throws Exception {
mvc.perform(MockMvcRequestBuilders.get("/test"))
.andExpect(MockMvcResultMatchers.status().isOk())
.andDo(MockMvcResultHandlers.print())
.andExpect(MockMvcResultMatchers.content().string("hello baymax"));
}
}
actuator Application Monitoring
spring actuator is provided monitoring application, the following configuration items common
# actuator端口 默认应用端口
management.server.port=8082
# 加载所有的端点 默认只加载 info,health
management.endpoints.web.exposure.include=*
# actuator路径前缀,默认 /actuator
management.endpoints.web.base-path=/actuator
chilli
lombok may generate a corresponding java code at compile the code look cleaner, while reducing development workload
Entity class after lombok
@Data
public class Demo {
private Long id;
private String userName;
private Integer age;
}
It should be noted, @Data
include @ToString、@Getter、@Setter、@EqualsAndHashCode、@RequiredArgsConstructor
, RequiredArgsConstructor not a constructor with no arguments , no-argument structure annotation isNoArgsConstructor
RequiredArgsConstructor
It generates a generated constant comprising a (final), and the construction method of identifying a variable @NotNull
baseEntity
The underlying field of the table pulled out a BaseEntity, all entity classes inherit the class
/**
* 实体类基础类
*/
@Data
public abstract class BaseEntity implements Serializable {
/**
* 主键id
*/
private Long id;
/**
* 创建人
*/
private Long createdBy;
/**
* 创建时间
*/
private Date createdTime;
/**
* 更新人
*/
private Long updatedBy;
/**
* 更新时间
*/
private Date updatedTime;
/**
* 是否删除
*/
private Integer isDeleted;
}
The return value unified response
Front and rear ends are separated project substantially ajax call, it returns a unified package objects facilitate distal unitary
/**
* 用于 ajax 请求的响应工具类
*/
@Data
public class ResponseResult<T> {
// 未登录
public static final String UN_LOGIN_CODE = "401";
// 操作失败
public static final String ERROR_CODE = "400";
// 服务器内部执行错误
public static final String UNKNOWN_ERROR_CODE = "500";
// 操作成功
public static final String SUCCESS_CODE = "200";
// 响应信息
private String msg;
// 响应code
private String code;
// 操作成功,响应数据
private T data;
public ResponseResult(String code, String msg, T data) {
this.msg = msg;
this.code = code;
this.data = data;
}
}
Returned to the front end of the value ResponseResult
-packaged
/**
* 测试成功的 ResponseResult
*/
@GetMapping("/successResult")
public ResponseResult<List<Demo>> test() {
List<Demo> demos = demoMapper.getDemos();
return ResponseResult.success(demos);
}
/**
* 测试失败的 ResponseResult
*/
@GetMapping("/errorResult")
public ResponseResult<List<Demo>> demo() {
return ResponseResult.error("操作失败");
}
ResponseEntity
In fact, the encapsulation process ResponseEntity spring response, the status code contains ResponseEntity header information, response body of three parts
/**
* 测试请求成功
* @return
*/
@GetMapping("/responseEntity")
public ResponseEntity<String> responseEntity() {
return ResponseEntity.ok("请求成功");
}
/**
* 测试服务器内部错误
* @return
*/
@GetMapping("/InternalServerError")
public ResponseEntity<String> responseEntityerror() {
return new ResponseEntity<>("出错了", HttpStatus.INTERNAL_SERVER_ERROR);
}
abnormal
Custom exception system
For convenience exception handling, an exception defined system, BaymaxException as all custom exception parent
// 项目所有自定义异常的父类
public class BaymaxException extends RuntimeException
// 业务异常 该异常的信息会返回给用户
public class BusinessException extends BaymaxException
// 用户未登录异常
public class NoneLoginException extends BaymaxException
Global exception handler
Returned to the front-end processing, then all exceptions
@RestControllerAdvice
public class GlobalControllerExceptionHandler {
/**
* 业务异常
*/
@ExceptionHandler(value = {BusinessException.class})
public ResponseResult<?> handleBusinessException(BusinessException ex) {
String msg = ex.getMessage();
if (StringUtils.isBlank(msg)) {
msg = "操作失败";
}
return ResponseResult.error(msg);
}
/**
* 处理未登录异常
*/
@ExceptionHandler(value = {NoneLoginException.class})
public ResponseResult<?> handleNoneLoginException(NoneLoginException ex) {
return ResponseResult.unLogin();
}
Abnormal persistence
For an unknown anomaly, saved to the database, to facilitate subsequent troubleshooting
It should be noted that, if the project access to larger than recommended ELK this sophisticated log analysis systems, is not recommended to save the log to a relational database
@Autowired
private ExceptionLogMapper exceptionLogMapper;
/**
* 处理未知的错误
*/
@ExceptionHandler(value = {Exception.class})
public ResponseResult<Long> handleunknownException(Exception ex) {
ExceptionLog log = new ExceptionLog(new Date(), ExceptionUtils.getStackTrace(ex));
exceptionLogMapper.insert(log);
ResponseResult<Long> result = ResponseResult.unknownError("服务器异常:" + log.getId());
result.setData(log.getId());
return result;
}
Interface exception log
Foreign exception log to open a query interface /anon/exception/{异常日志id}
, easy access
@RestController
@RequestMapping("/anon/exception")
public class ExceptionController {
@Autowired
private ExceptionLogMapper exceptionLogMapper;
@GetMapping(value = "/{id}")
public String getDemo(@PathVariable(value = "id") Long id) {
return exceptionLogMapper.selectByPrimaryKey(id).getException();
}
}
Data validation
JSR 303 defines a set of Bean Validation specification, Hibernate Validator is to achieve Bean Validation and was extended
spring boot is also very easy to use
public class Demo extends BaseEntity{
@NotBlank(message = "用户名不允许为空")
private String userName;
@NotBlank
private String title;
@NotNull
private Integer age;
}
Notes can be added before the parameter @Valid
@PostMapping("/add")
public ResponseResult<String> add(@RequestBody @Valid Demo demo) {
demoMapper.insert(demo);
return ResponseResult.success();
}
For each method alone can check the results of treatment, if not addressed, will throw an exception, an exception can be made to check the global process
In GlobalControllerExceptionHandler
add
/**
* 处理校验异常
*/
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseResult<?> handleValidationException(MethodArgumentNotValidException ex) {
BindingResult result = ex.getBindingResult();
if (result.hasErrors()) {
StringJoiner joiner = new StringJoiner(",");
List<ObjectError> errors = result.getAllErrors();
errors.forEach(error -> {
FieldError fieldError = (FieldError) error;
joiner.add(fieldError.getField() + " " + error.getDefaultMessage());
});
return ResponseResult.error(joiner.toString());
} else {
return ResponseResult.error("操作失败");
}
}
log
The default spring boot log is used logback
, web logs are dependent module starter
, so here no longer dependent on the introduction, detailed configuration
Change the log level
Actuator component provides a log-related interfaces, you can query the log level or dynamically change the log level
// 查看所有包/类的日志级别
/actuator/loggers
// 查看指定包/类日志级别 get 请求
/actuator/loggers/com.zhaoguhong.baymax.demo.controller.DemoController
//修改日志级别 post 请求 参数 {"configuredLevel":"debug"}
/actuator/loggers/com.zhaoguhong.baymax.demo.controller.DemoController
Logs cut
One log section, convenient method for performing recording of the parameters and the parameters
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface LogAspect {
/**
* 日志描述
*/
String value() default "";
/**
* 日志级别
*/
String level() default "INFO";
}
Directly added to the method to use
swagger
swagger document generation tool is a good use of
maven dependence
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.7.0</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.7.0</version>
</dependency>
Related
@Configuration
@EnableSwagger2
public class SwaggerConfig {
@Value("${swagger.enable:false}")
private boolean swaggerEnable;
//文档访问前缀
public static final String ACCESS_PREFIX = "/swagger-resources/**,/swagger-ui.html**,/webjars/**,/v2/**";
@Bean
public Docket docket() {
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
// 设置是否开启swagger,生产环境关闭
.enable(swaggerEnable)
.select()
// 当前包路径
.apis(RequestHandlerSelectors.basePackage("com.zhaoguhong.baymax"))
.apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class))
.paths(PathSelectors.any())
.build();
}
// 构建api文档的详细信息
private ApiInfo apiInfo() {
return new ApiInfoBuilder()
// 页面标题
.title("接口文档")
// 创建人
.contact(new Contact("孤鸿", "https://github.com/zhaoguhong/baymax", ""))
// 版本号
.version("1.0")
// 描述
.description("大白的接口文档")
.build();
}
}
The document plus a switch
#是否开启swagger文档,生产环境关闭
swagger.enable=true
Then you can have fun at the same time writing code written documentation of the
@PostMapping("/add")
@ApiOperation(value = "新增 demo")
public ResponseResult<String> add(@RequestBody @Valid Demo demo) {
demoMapper.insert(demo);
return ResponseResult.success();
}
@ApiModel("示例")
public class Demo extends BaseEntity{
@ApiModelProperty("用户名")
private String userName;
@ApiModelProperty("标题")
private String title;
@ApiModelProperty("年龄")
private Integer age;
}
Access localhost:8080/swagger-ui.html
can see the effect of
Database connection pool
springboot1.X database connection pool is tomcat connection pooling, springboot2 default database connection pool by the Tomcat replaced HikariCP , HikariCP
is a high-performance JDBC connection pool, known as the fastest connection pool
Druid Alibaba database division produced, to monitor the health of the database connection pool, here selected Druid
as a project database connection pool
maven dependence
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.10</version>
</dependency>
Set Username Password
spring.datasource.druid.stat-view-servlet.login-username=admin
spring.datasource.druid.stat-view-servlet.login-password=123456
Then you can visit localhost:8080/druid
to see the monitoring information
spring jdbc
maven dependence
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
jdbc spring to do encapsulation and abstraction, the most commonly used jdbcTemplate
and NamedParameterJdbcTemplate
two categories, the former with a placeholder, which uses named parameters, I jdbcDao
made one simple package, providing a unified external interface
jdbcDao
The main methods are as follows:
// 占位符
find(String sql, Object... args)
// 占位符,手动指定映射mapper
find(String sql, Object[] args, RowMapper<T> rowMapper)
// 命名参数
find(String sql, Map<String, ?> paramMap)
// 命名参数,手动指定映射mapper
find(String sql, Map<String, ?> paramMap, RowMapper<T> rowMapper)
//springjdbc 原queryForMap方法,如果没查询到会抛异常,此处如果没有查询到,返回null
queryForMap(String sql, Object... args)
queryForMap(String sql, Map<String, ?> paramMap)
// 分页查询
find(Page<T> page, String sql, Map<String, ?> parameters, RowMapper<?> mapper)
// 分页查询
find(Page<T> page, String sql, RowMapper<T> mapper, Object... args)
jpa
jpa
Is the java
persistence of standards, spring data jpa
so that database operations more convenient, a description of spring data jpa
itself is not achieved jpa, which is used by default provider
ishibernate
maven dependence
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
I put common method to extract out, and encapsulates a BaseRepository, when in use, the interface can be directly inherited
public interface DemoRepository extends BaseRepository<Demo> {
}
BaseRepository
The main methods are as follows
// 新增,会对创建时间,创建人自动赋值
void saveEntity(T entity)
// 更新,会对更新时间,更新人自动赋值
void updateEntity(T entity)
// 逻辑删除
void deleteEntity(T entity)
// 批量保存
void saveEntites(Collection<T> entitys)
// 批量更新
void updateEntites(Collection<T> entitys)
// 批量逻辑删除
void deleteEntites(Collection<T> entitys)
// 根据id获取实体,会过滤掉逻辑删除的
T getById(Long id)
If you want to use sql traditional form, it can be used directly JpaDao, for convenience, I try to make JpaDao and JdbcDao interface to maintain unity
JpaDao
The main methods are as follows
// 占位符 例如:from Demo where id =?
find(String sql, Object... args)
// 命名参数
find(String sql, Map<String, ?> paramMap)
// 分页
find(Page<T> page, String hql, Map<String, ?> parameters)
// 分页
find(Page<T> page, String hql, Object... parameters)
repeat
Redis excellent performance is key-value databases, often used for caching,
Java client has commonly used Jedis
and Lettuce
, spring data redis
based on Lettuce
doing the second package
maven dependence
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
To read more convenient redis, change the serialization
@Configuration
public class RedisConfig {
/**
* 设置序列化方式
*/
@Bean
public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(redisConnectionFactory);
redisTemplate.setKeySerializer(RedisSerializer.string());
redisTemplate.setValueSerializer(jackson2JsonRedisSerializer());
redisTemplate.setHashKeySerializer(RedisSerializer.string());
redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer());
return redisTemplate;
}
@Bean
public Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer() {
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
// 将类名称序列化到json串中
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer =
new Jackson2JsonRedisSerializer<Object>(Object.class);
jackson2JsonRedisSerializer.setObjectMapper(om);
return jackson2JsonRedisSerializer;
}
}
spring cache
abstract spring cache a set of cache interface, by way of the use of annotations, can easily configure a specific implementation, detailed configuration
Redis used here as a cache provider, the default value serialization is JDK, for the convenience of viewing, can be modified to use json serialization
Sometimes set redis key
prefix demand, this is the default
static CacheKeyPrefix simple() {
// 在 cacheName 后面添加 "::"
return name -> name + "::";
}
There prefix property spring boot configuration provided
spring.cache.redis.key-prefix= # Key prefix.
But this is a pit, write the actual effect of this, will cacheName
get rid of, is clearly not what we want
CacheKeyPrefix cacheKeyPrefix = (cacheName) -> prefix;
What we want is to add the prefix in front, reservedcacheName
CacheKeyPrefix cacheKeyPrefix = (cacheName) -> keyPrefix + "::" + cacheName + "::";
Reference org.springframework.boot.autoconfigure.cache.RedisCacheConfiguration
, statementRedisCacheManager
@Configuration
@EnableConfigurationProperties(CacheProperties.class)
@EnableCaching
public class SpringCacheConfig {
@Autowired
private CacheProperties cacheProperties;
@Bean
public RedisCacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) {
RedisCacheManagerBuilder builder = RedisCacheManager
.builder(redisConnectionFactory)
.cacheDefaults(determineConfiguration());
List<String> cacheNames = this.cacheProperties.getCacheNames();
if (!cacheNames.isEmpty()) {
builder.initialCacheNames(new LinkedHashSet<>(cacheNames));
}
return builder.build();
}
private org.springframework.data.redis.cache.RedisCacheConfiguration determineConfiguration() {
Redis redisProperties = this.cacheProperties.getRedis();
org.springframework.data.redis.cache.RedisCacheConfiguration config = org.springframework.data.redis.cache.RedisCacheConfiguration
.defaultCacheConfig();
// 修改序列化为json
config = config.serializeValuesWith(RedisSerializationContext.SerializationPair
.fromSerializer(jackson2JsonRedisSerializer()));
if (redisProperties.getTimeToLive() != null) {
config = config.entryTtl(redisProperties.getTimeToLive());
}
if (redisProperties.getKeyPrefix() != null) {
// 重写前缀拼接方式
config = config.computePrefixWith((cacheName) -> redisProperties.getKeyPrefix() + "::" + cacheName + "::");
}
if (!redisProperties.isCacheNullValues()) {
config = config.disableCachingNullValues();
}
if (!redisProperties.isUseKeyPrefix()) {
config = config.disableKeyPrefix();
}
return config;
}
// 省略 jackson2JsonRedisSerializer()
}
mogodb
MongoDB is a document database, using spring data mogodb
easy to operate mogodb
maven dependence
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
sprign data mogodb
Provides MongoTemplate
for mogodb operate on the basis of class I and expands on it, you can customize your own method
@Configuration
public class MongoDbConfig {
/**
* 扩展自己的mogoTemplate
*/
@Bean
public MyMongoTemplate mongoTemplate(MongoDbFactory mongoDbFactory,
MongoConverter converter) {
return new MyMongoTemplate(mongoDbFactory, converter);
}
}
I extend a way paging, other methods can be extended depending on your situation
// mogodb 分页
public <T> Page<T> find(Page<T> page, Query query, Class<T> entityClass)
mybatis
maven dependence
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.3.2</version>
</dependency>
Common configured as follows
# 配置文件位置 classpath后面要加*,不然后面通配符不管用
mybatis.mapperLocations=classpath*:com/zhaoguhong/baymax/*/mapper/*Mapper.xml
# 开启驼峰命名自动映射
mybatis.configuration.map-underscore-to-camel-case=true
dao layer directly interfaces, simple, easy
@Mapper
public interface DemoMapper {
/**
* 注解方式
*/
@Select("SELECT * FROM demo WHERE user_name = #{userName}")
List<Demo> findByUserName(@Param("userName") String userName);
/**
* xml方式
*/
List<Demo> getDemos();
}
It should be noted, the xml namespace must be a fully qualified name mapper class, so that it can establish a relationship of dao interface xml
<mapper namespace="com.zhaoguhong.baymax.demo.dao.DemoMapper">
<select id="getDemos" resultType="com.zhaoguhong.baymax.demo.entity.Demo">
select * from demo
</select>
</mapper>
General mapper
mybatis single-table CRUD to write very much, General mapper good solution to this problem
maven dependence
<dependency>
<groupId>tk.mybatis</groupId>
<artifactId>mapper-spring-boot-starter</artifactId>
<version>1.2.4</version>
</dependency>
Common configured as follows
# 通用mapper 多个接口时用逗号隔开
mapper.mappers=com.zhaoguhong.baymax.mybatis.MyMapper
mapper.not-empty=false
mapper.identity=MYSQL
Define their own MyMapper
convenience extension, MyMapper
the interface encapsulates common methods, and jpa
of BaseRepository
the like, not repeated here
Statement mapper
need to add Mapper
annotations, but also somewhat cumbersome, you can use the scan mode
@Configuration
@tk.mybatis.spring.annotation.MapperScan(basePackages = "com.zhaoguhong.baymax.**.dao")
public class MybatisConfig {
}
The direct successor MyMapper interface can use
public interface DemoMapper extends MyMapper<Demo>{
}
Paging
pagehelper is paged plug mybatis of a good use of
maven dependence
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
<version>1.2.3</version>
</dependency>
Common configured as follows
#pagehelper
#指定数据库类型
pagehelper.helperDialect=mysql
#分页合理化参数
pagehelper.reasonable=true
Use pagination
PageHelper.startPage(1, 5);
List<Demo> demos = demoMapper.selectAll();
pagehelper there are a lot of play, you can refer here
Custom Paging
pagehelper Although easy to use, but the project has its own page objects, so writing a single interceptor, integrate them together into
this place pay special attention to the plug-in order not to mistake
@Configuration
// 设置mapper扫描的包
@tk.mybatis.spring.annotation.MapperScan(basePackages = "com.zhaoguhong.baymax.**.dao")
@Slf4j
public class MybatisConfig {
@Autowired
private List<SqlSessionFactory> sqlSessionFactoryList;
/**
* 添加自定义的分页插件,pageHelper 的分页插件PageInterceptor是用@PostConstruct添加的,自定义的应该在其后面添加
* 真正执行时顺序是反过来,先执行MyPageInterceptor,再执行 PageInterceptor
*
* 所以要保证 PageHelperAutoConfiguration 先执行
*/
@Autowired
public void addPageInterceptor(PageHelperAutoConfiguration pageHelperAutoConfiguration) {
MyPageInterceptor interceptor = new MyPageInterceptor();
for (SqlSessionFactory sqlSessionFactory : sqlSessionFactoryList) {
sqlSessionFactory.getConfiguration().addInterceptor(interceptor);
log.info("注册自定义分页插件成功");
}
}
}
When using only need to pass self-defined objects can be paged
Page<Demo> page = new Page<>(1, 10);
demos = demoMapper.getDemos(page);
spring security
The security module is an indispensable part of the project, common security framework shiro
and spring security
, shiro relatively lightweight, very flexible, spring security
relatively function better, but also seamless and spring. Here select spring security
as Security Framework
maven dependence
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
WebSecurityConfigurerAdapter class inheritance can be configured
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private SecurityProperties securityProperties;
@Autowired
private UserDetailsService userDetailsService;
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
// 设置可以匿名访问的url
.antMatchers(securityProperties.getAnonymousArray()).permitAll()
// 其它所有请求都要认证
.anyRequest().authenticated()
.and()
.formLogin()
// 自定义登录页
.loginPage(securityProperties.getLoginPage())
// 自定义登录请求路径
.loginProcessingUrl(securityProperties.getLoginProcessingUrl())
.permitAll()
.and()
.logout()
.permitAll();
// 禁用CSRF
http.csrf().disable();
}
@Override
public void configure(WebSecurity web) throws Exception {
String[] ignoringArray = securityProperties.getIgnoringArray();
// 忽略的资源,直接跳过spring security权限校验
if (ArrayUtils.isNotEmpty(ignoringArray)) {
web.ignoring().antMatchers(ignoringArray);
}
}
/**
*
* 声明密码加密方式
*/
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Override
protected void configure(AuthenticationManagerBuilder auth)
throws Exception {
auth.userDetailsService(userDetailsService)
// 配置密码加密方式,也可以不指定,默认就是BCryptPasswordEncoder
.passwordEncoder(passwordEncoder());
}
}
Implement UserDetailsService
an interface, define your ownUserDetailsService
@Service
public class UserDetailsServiceImpl implements UserDetailsService {
@Autowired
private UserRepository userRepository;
@Override
@Transactional
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = userRepository.findByUsernameAndIsDeleted(username, SystemConstants.UN_DELETED);
if (user == null) {
throw new UsernameNotFoundException("username Not Found");
}
return user;
}
}
Configuration Item
#匿名访问的url,多个用逗号分隔
security.anonymous=/test
#忽略的资源,直接跳过spring security权限校验,一般是用做静态资源,多个用逗号分隔
security.ignoring=/static/**,/images/**
#自定义登录页面
security.loginPage=/login.html
#自定义登录请求路径
security.loginProcessingUrl=/login
Project context
For the use, a context object encapsulating ContextHolder
// 获取当前线程HttpServletRequest
getRequest()
// 获取当前线程HttpServletResponse
getResponse()
// 获取当前HttpSession
getHttpSession()
setSessionAttribute(String key, Serializable entity)
getSessionAttribute(String key)
setRequestAttribute(String key, Object entity)
getRequestAttribute(String key)
// 获取 ApplicationContext
getApplicationContext()
//根据beanId获取spring bean
getBean(String beanId)
// 获取当前登录用户
getLoginUser()
// 获取当前登录用户 id
getLoginUserId()
// 获取当前登录用户 为空则抛出异常
getRequiredLoginUser()
// 获取当前登录用户id, 为空则抛出异常
getRequiredLoginUserId()
sign in
SSO (SSO, single sign-on) means, a plurality of systems share a set of system users, as long as one of the system log, the system does not need to re-login access to other
CASE
CAS (Central Authentication Service) is an open source project at Yale University, is the more popular single sign-on solution. In the CAS system, is responsible only for login is called the server, all other systems are referred to as client
Login process
- Users access the client, the client determines whether the login, if not logged in, redirect to login to the server
- Server login is successful, with ticket redirected to the client
- The client sends a request took the ticket to the server in exchange for user information, access to representation after a successful login
Logout Process
Jump to sso unified authentication center out, cas will notify all clients to logout
spring security integration cas
maven dependence
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-cas</artifactId>
</dependency>
spring security for cas done a very good package, use of the process, only need to define the corresponding login and logout fifter fifter can integrate cas code I wrote in a WebSecurityConfig
class
Related property configuration
#是否开启单点登录
cas.enable = true
#服务端地址
cas.serverUrl=
#客户端地址
cas.clientUrl=
#登录地址
cas.loginUrl=${cas.serverUrl}/login
#服务端登出地址
cas.serverLogoutUrl=${cas.serverUrl}/logout
#单点登录成功回调地址
cas.clientCasUrl=${cas.clientUrl}/login/cas
To use the template as freeMarker resolve, so it will depend on the introduction of freeMarker
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
</dependency>
Related
#邮件
#设置邮箱主机,163邮箱为smtp.163.com,qq为smtp.qq.com
spring.mail.host = smtp.163.com
spring.mail.username =
#授权码
spring.mail.password =
#默认的邮件发送人
mail.sender =
A package MailService
// 根据相关配置发送邮件
void sendMail(MailModel mailModel);
// 发送简单的邮件
void sendSimleMail(String to, String subject, String content);
// 发送html格式的邮件
void sendHtmlMail(String to, String subject, String content);
// 发送带附件的邮件
void sendAttachmentMail(String to, String subject, String content, String path);
// 发送带附件的html格式邮件
void sendAttachmentHtmlMail(String to, String subject, String content, String path);
// 根据模版发送简单邮件
void sendMailByTemplate(String to, String subject, String templateName,
Map<String, Object> params);
}
maven
Mirroring
Set Ali cloud images, faster downloads
modify setting.xml, on the mirrors node, add
<mirror>
<id>alimaven</id>
<name>aliyun maven</name>
<url>http://maven.aliyun.com/nexus/content/groups/public/</url>
<mirrorOf>central</mirrorOf>
</mirror>
You can also add in the project pom.xml file, only the current project effective
<repositories>
<repository>
<id>alimaven</id>
<name>aliyun maven</name>
<url>http://maven.aliyun.com/nexus/content/groups/public/</url>
<releases>
<enabled>true</enabled>
<updatePolicy>daily</updatePolicy>
</releases>
<snapshots>
<enabled>false</enabled>
<checksumPolicy>warn</checksumPolicy>
</snapshots>
<layout>default</layout>
</repository>
</repositories>
to sum up
- follow the principle of spring boot out of the box, do not need to do too much, tutorials, online quality is uneven, and when 1.X and 2.X there are many different use, so the use of reference as far as possible the official document
- Sometimes the default configuration does not meet our needs, need to do some custom configuration, recommend a look at the
springboot
source code automatically configured, do the customization process - Technology is no silver bullet, when making technology selection Do not rely too much on a technology suited to their business technology is the best