springboot学完这些就够了

springboot-02-config

      yml和properties两种配置文件的不同,yaml中-些属性的书写格式,包括实体类、数组、map、 set、 引入外部类
      实体类要通过@Component将该类注入到spring容器中,
      若将配置文件中的值赋值给容器中的变量,若为yml格式 要通过@ConfigurationProperties(prefix=" person")格式引入
application.yaml

person:
  name: 小明
  age: 12
  hobbies: [sing,dance,show]
  sports: [bas,足球,ping]
  map: {1: 小王,2: 小刘}
  dog:
    name: 金毛
    age: 5
  date: 2020/08/07

person.class外部引入application.yaml配置文件


@Data
@NoArgsConstructor
@AllArgsConstructor
@Component
//prefix = "person"和ymal声明的实体类person进行绑定起来
@ConfigurationProperties(prefix = "person")
@Validated//数据校验
/*@PropertySource(value = "classpath:application.properties")*/
public class Person {


	/*@Email*/
	/*@Value("张哲${random.uuid}")*/
	private String name;
	/*@Value("${random.int}")*/
	private Integer age;
	/*@Value("#{9+2}")*/
	private Integer heigh;
	private String[] hobbies;
	private List<String> sports;
	private Map map;
	private Dog dog;
	private Date date;
}

       若properties文件要引入@PropertySources(value= "classpath:application.properties")并且通过@Value(" ")变量赋值,其中可以引入数据校验@Validated
      ym|配置文件的多环境切换,通过"--- "就可以实现在一个yml文件中实现多环境切换, 其中spring:profiles:dev为标识该环境,通过spring:profiles:active:dev激活该环境
      深度分析了自动配置源码的实现原理HttpEncodingAutoConfig

springboot-03-web

      主要讲了静态页面的访问,引入静态资源有两种方式
(1)通过导入webjars依赖, 访问该依赖下webjars下的静态资源;

<!--引入webjars-->
        <dependency>
            <groupId>org.webjars</groupId>
            <artifactId>jquery</artifactId>
            <version>3.5.1</version>
        </dependency>

(2)还有就是把静态资源放到resources、static、 public、(优先级逐渐降低)下面也能访问到静态页面,但一般把静态样式css、js、 img都放到static下面;一般欢迎页放在public下面,以index.html的形式命名;
      还有templates包下放主要的html页面,通过控制器、跳转到该下的页面
      引入模板引擎thymeleaf依赖还有一些用法 th:text、th:each、 th:if

<!--引入webjars-->
        <dependency>
            <groupId>org.webjars</groupId>
            <artifactId>jquery</artifactId>
            <version>3.5.1</version>
        </dependency>

      扩展mvc @Configuration配置类的详细讲解包括自定义解析器实现ViewResolver接口、实现自定义视图跳转重写addViewControllers方法、格式化Format等 最后详细讲解了@EnableWebMvc注解

springboot-03-crud(实现了增删改查)

      实现了数据的增删改查操作,其中包含了很多知识点比如restful风格的使用

      国际化(实现LocaleResolver接口并将该类@Bean到MyMvcConfig类中)
      登录的截操作(实现HandlerInterceptor并在MyMvcConfig类中重写addInterceptors方法并注入自定义的拦截类)这些都需要在MyMvbcConfig配置类中
国际化
1.在resources包下面,创建i18n包( internationalization)缩写
2.创建login.properties配置文件和login_zh_CN.properties配置文件,自动帮我们整合在了一个包下面
在这里插入图片描述
3.接下来我们右键Resource Bundle 'login’创建login_en_US.properties
在这里插入图片描述在这里插入图片描述
4.接下来我们在配置文件中添加内容 这里的login.xxx只是我们起的别名,方便前台根据#{login.xxx}取到国际化的值
在这里插入图片描述
配置完成
在这里插入图片描述

代码实现国际化的转换
来看下MessageSourceAutoConfiguration这个类
在这里插入图片描述
打开MessageSourceProperties这个类
在这里插入图片描述
application.properties 找到了国际化的配置文件
#国际化 配置的位置spring.messages.basename=i18n.login
前台页面取国际化的值,我们根据thymeleaf模板引擎语法,用#{}来拿国际化的值

这样很难操控中英文变换,接下来我们通过按钮实现切换语言
这里th:href="@{/(l='zh_CN')}"就请求的路径就为/?l=zh_CN
在这里插入图片描述在这里插入图片描述
首先我们看下源码,打开webMvcConfiguration找到localeResolver这个类
在这里插入图片描述
在这里插入图片描述
总之要实现国际化,我们需要自定义一个组件LocalResolver
把自定义的组件配置到spring容器中去 @Bean

public class MyLocaleResolver implements LocaleResolver {
	//实现国际化
	@Override
	public Locale resolveLocale(HttpServletRequest request) {
		//获得前台的请求参值的链接
		String language = request.getParameter("l");
		//System.out.println("----->"+language);
		//如果没有就使用默认的
		Locale locale = Locale.getDefault();

		//如果请求的参数不为空,且携带了国际化的参数zh_CN  en_US 就分隔出来
		if (!StringUtils.isEmpty(language)){

			//分隔字符串
			String[] split = language.split("_");
			// zh_CN 国家 地区
			locale = new Locale(split[0], split[1]);

		}
		return locale;
	}

	@Override
	public void setLocale(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Locale locale) {

	}
}

把自定义的组件配置到spring容器中去

@Configuration
public class MyMvcConfig implements WebMvcConfigurer {
//注册国际化组件 放到spring容器中 才生效
	@Bean
	public LocaleResolver localeResolver() {
		return new MyLocaleResolver();
	}
}

实现登录,

	@RequestMapping("/user/login")
	public String login(@RequestParam("username") String name,
						@RequestParam("password") String pwd,
						Model model, HttpSession session) {

		if (!StringUtils.isEmpty(name) && "123".equals(pwd)) {
			//登录成功 跳转首页
			session.setAttribute("loginUser", name);
			return "redirect:/main.html";
		} else {
			//登陆失败 跳转到 登录页面 并携带错误信息
			model.addAttribute("msg", "用户名不存或密码错误");

			return "index";
		}
	}

MyMvcConfig.class

@Configuration
public class MyMvcConfig implements WebMvcConfigurer {


	@Override
	public void addViewControllers(ViewControllerRegistry registry) {
		// 一般跳转到 首页用自定义跳转请求
		//请求跳转到 主页面 和控制器作用相同
		registry.addViewController("/").setViewName("index");
		//urlPath:是控制器返回的伪路径,setViewName跳转的页面,dashboard.html
		/*
		     这样进行跳转的好处 1.浏览器不在出现真实的访问路径,安全性提高
		     				  2. 若大量的页面跳转到该页面,可读性高

		 */
		registry.addViewController("/main.html").setViewName("dashboard");
	}

自定义public void addViewControllers(ViewControllerRegistry registry) 方法,就是中转了一下控制器的请求路径,使浏览器不出现真实的请求路径,那么这样就实现了登录的操作,肯定是不安全的,否则不登录就能进入首页,接下来实现拦截器操作。
拦截操作
自定义HandlerInterceptor的实现类,这是springmvc的一个拦截操作

public class loginHandlerInterceptor implements HandlerInterceptor {
	@Override
	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
	     //登录成功后获得用户的session
		Object loginUser = request.getSession().getAttribute("loginUser");
		//System.out.println("user=====>"+loginUser);

		if (loginUser == null) {
			//拦截
			request.setAttribute("msg", "没有权限访问.请先登录");
			//转发到 登录页面
			request.getRequestDispatcher("/").forward(request, response);
			return false;
		} else {
			return true;
		}
	}
}

重写WebMvcConfigurer 拦截器的实现方法addInterceptors并将自定义的拦截器@Bean到spring容器中
注册 自定义类

@Configuration
public class MyMvcConfig implements WebMvcConfigurer {


	@Override
	public void addViewControllers(ViewControllerRegistry registry) {
		// 一般跳转到 首页用自定义跳转请求
		//请求跳转到 主页面 和控制器作用相同
		registry.addViewController("/").setViewName("index");
		registry.addViewController("/main.html").setViewName("dashboard");


	}

	//注册国际化组件 放到spring容器中 才生效
	@Bean
	public LocaleResolver localeResolver() {
		return new MyLocaleResolver();
	}

	/*//拦截器
	@Override
	public void addInterceptors(InterceptorRegistry registry) {
		registry.addInterceptor(new loginHandlerInterceptor()).addPathPatterns("/**")
				// 拦截...请求 并且放行...请求
				.excludePathPatterns("/", "/index.html", "/user/login", "/css/**", "js/**", "img/**");
	}*/
	
	@Bean
	public HandlerInterceptor handlerInterceptor() {
		return new loginHandlerInterceptor();
	}

	//拦截器
	@Override
	public void addInterceptors(InterceptorRegistry registry) {
		registry.addInterceptor(handlerInterceptor()).addPathPatterns("/**")
				// 拦截...请求 并且放行...请求
				.excludePathPatterns("/", "/index.html", "/user/login", "/css/**", "js/**", "img/**");
	}
}

      注册组件;前端抽取公共页面(详情见thymeleaf文档8.0)
要抽取的片段


	<div th:fragment="city"></div>
	或者
	<div id="city"><</div>

要引入的片段

//三种形式:th:insert、th:replace、th:include 其中th:replace使用频率更广
<div th:replace="commo/bar::city"></div>
或者
<div th:replace="commo/bar::#city"></div>

      修改数据时运用resultful风格的put提交表单时,要实现这段代码

html<input type= "hidden" name=" method" value=" put" th:if="${emp!=null}">`

springboot-04-jdbc(整合jdbc和引入druid数据源)

      整合了jdbc 在yml文件中注册了jdbc的四大驱动,还有将数据源更改成为了druid数据源,并添加了后台监控器 和web过滤器
注意要引入druidlog4j依赖

		<!--druid-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.21</version>
        </dependency>

        <!--log4j-->
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>

在.yml文件中引入jdbc四大驱动 及druid数据源专有配置

spring:
  datasource:
    username: root
    password: '061298'
    url: jdbc:mysql://localhost:3306/mybaits?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8
    driver-class-name: com.mysql.cj.jdbc.Driver
    ##更换为druid 数据源
    type: com.alibaba.druid.pool.DruidDataSource


    #Spring Boot 默认是不注入这些属性值的,需要自己绑定
    #druid 数据源专有配置
    initialSize: 5
    minIdle: 5
    maxActive: 20
    maxWait: 60000
    timeBetweenEvictionRunsMillis: 60000
    minEvictableIdleTimeMillis: 300000
    validationQuery: SELECT 1 FROM DUAL
    testWhileIdle: true
    testOnBorrow: false
    testOnReturn: false
    poolPreparedStatements: true

    #配置监控统计拦截的filters,stat:监控统计、log4j:日志记录、wall:防御sql注入
    #如果允许时报错  java.lang.ClassNotFoundException: org.apache.log4j.Priority
    #则导入 log4j 依赖即可,Maven 地址:https://mvnrepository.com/artifact/log4j/log4j
    filters: stat,wall,log4j
    maxPoolPreparedStatementPerConnectionSize: 20
    useGlobalDataSourceStat: true
    connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500

后台监控和wb过滤器

@Configuration
public class DruidMyConfig {

	/*
	  将自定义的 Druid数据源添加到容器中,不再让 Spring Boot 自动创建
	  绑定全局配置文件中的 druid 数据源属性到 com.alibaba.druid.pool.DruidDataSource从而让它们生效
	  @ConfigurationProperties(prefix = "spring.datasource"):作用就是将 全局配置文件中
	  前缀为 spring.datasource的属性值注入到 com.alibaba.druid.pool.DruidDataSource 的同名参数中
	*/
	@ConfigurationProperties(prefix = "spring.datasource")
	@Bean
	public DataSource druidDataSource(){
		return new DruidDataSource();
	}

	//后台监控 相当于web.xml
	// 因为springboot内置了 servlet容器 所以没有web.xml  ServletRegistrationBean 替代了xml
	@Bean
	public ServletRegistrationBean servletRegistrationBean(){
		ServletRegistrationBean<StatViewServlet> bean=new ServletRegistrationBean<>(new StatViewServlet(),"/druid/*");

		//后台需要有人登陆 账号密码
		Map<String, String> initParameters = new HashMap<>();

		//增加配置
		//登陆key 是固定的 不能变
		initParameters.put("loginUsername","admin");
		initParameters.put("loginPassword","123456");

		//允许谁访问  空代表所有人
		initParameters.put("allow","");


		//设置初始化 参数
		bean.setInitParameters(initParameters);
		return bean;
	}


	//过滤器
	@Bean
	public FilterRegistrationBean webStatFilter(){
		FilterRegistrationBean<Filter> bean = new FilterRegistrationBean<>();

		bean.setFilter(new WebStatFilter());

		//过滤哪些请求
		Map<String,String> initParameters = new HashMap<>();

		//这些请求 不需要过滤
		initParameters.put("exclusions","*.js,*.css,/druid/*");

		bean.setInitParameters(initParameters);
		return bean;
	}
}

Controller处理业务 没有整合mybatis

@RestController
public class JdbcController {

	@Autowired
	private JdbcTemplate jdbcTemplate;

	@RequestMapping("/select")
	public String select() {
		String sql = "select * from mybaits.blog";
		List<Map<String, Object>> maps = jdbcTemplate.queryForList(sql);
		return maps.toString();
	}

	@RequestMapping("/insert")
	public String add() {
		String sql = "insert into mybaits.blog(id,title,author,create_time) values(6,'你好','张哲','2020-05-06')";
		jdbcTemplate.update(sql);
		return "添加成功";
	}

	@RequestMapping("/del/{id}")
	public String del(@PathVariable("id") Integer id) {
		String sql = "delete from mybaits.blog where id=?";
		jdbcTemplate.update(sql,id);
		return "删除成功";
	}                                                                                                                                                                                                                                      

	@RequestMapping("/update/{id}")
	public String update(@PathVariable("id") Integer id) {
		String sql = "update mybaits.blog set title='王道',author='小王' where id="+id;
		jdbcTemplate.update(sql);
		return "修改成功";
	}
}

springboot-05-mybatis(整合mybatis)

引入mybatis-springboot依赖

 		  <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        
        <!--mybatis自己的一个依赖 不属于springboot-->
 		 <!--`mybatis-springboot-->
 		<dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.1.1</version>
        </dependency>
        
		 <!--druid-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.21</version>
        </dependency>

        <!--log4j-->
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>

这里不需要引入spring-boot-starter-jdbc依赖,因为引入的mysql-connector-java依赖已经含有jdbc配置
在这里插入图片描述
application.yml

spring:
  datasource:
    username: root
    password: '061298'
    url: jdbc:mysql://localhost:3306/mybaits?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8
    driver-class-name: com.mysql.cj.jdbc.Driver
   
    type: com.alibaba.druid.pool.DruidDataSource
    initialSize: 5
    minIdle: 5
    maxActive: 20
    maxWait: 60000
    timeBetweenEvictionRunsMillis: 60000
    minEvictableIdleTimeMillis: 300000
    validationQuery: SELECT 1 FROM DUAL
    testWhileIdle: true
    testOnBorrow: false
    testOnReturn: false
    poolPreparedStatements: true

  
    filters: stat,wall,log4j
    maxPoolPreparedStatementPerConnectionSize: 20
    useGlobalDataSourceStat: true
    connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500

mybatis:
  type-aliases-package: com.zz.pojo
  mapper-locations: classpath:mapper/*.xml
  #引入mybatis核心文件
  #config-location:

创建各种包
在这里插入图片描述
UserMapper.java(注意要在Mapper接口类中添加@Mapper注解)

//表示本类是一个 Mapper接口类 相当于注册到了spring容器中
@Mapper
@Repository

public interface UserMapper {

	List<User> getAllUser();

	User getUserById(@PathVariable("id") Integer id);

	int addUser(User user);

	int delUserById(@PathVariable("id") Integer id);

	int updateUser(User user);
}

或者 在主程序了中添加```@MapperScan(“com.zz.mapper”)``注解

@SpringBootApplication
//相当于@Mapper注解
//@MapperScan("com.zz.mapper")
public class Springboot05MybatisApplication {

	public static void main(String[] args) {
		SpringApplication.run(Springboot05MybatisApplication.class, args);
	}
}

UserMapper.xml文件 一般 写在resources 也可以和UserMapper.java在同一包下面
在这里插入图片描述
UserMapper.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.zz.mapper.UserMapper">
    <select id="getAllUser" resultType="User">
        select * from mybaits.user;
    </select>

    <select id="getUserById" resultType="User">
        select * from mybaits.user where id=#{id};
    </select>

    <insert id="addUser" parameterType="User">
        insert into mybaits.user(id, name, pwd) values (#{id},#{name},#{pwd})
    </insert>

    <delete id="delUserById" >
        delete from mybaits.user where id=#{id}
    </delete>

    <update id="updateUser" parameterType="User">
        update mybaits.user set name=#{name},pwd=#{pwd} where id=#{id}

    </update>
</mapper>

注册结果集mapper映射 要在.yml文件中

mybatis:
  type-aliases-package: com.zz.pojo
  mapper-locations: classpath:mapper/*.xml
  #classpath:表示resources这一目录下的文件
  #引入mybatis核心文件
  #config-location:classpath:mybatis.xml

或者定义一个mybatis.xml配置文件 通过config-location:.yml中引入
注意classpath:后面不需要添加空格 直接写resource下的文件名

注意:当数据库的字段值以下划线,实体类中的属性以驼峰形式命名时,这时候就访问不到该字段数据库中的值了
实体类中属性值:private String userName
数据库中字段值:user_name
为了能正常取到数据库中该字段的值,要解决这一问题其中之一就是在配置文件做手动配置 接下来我们先来看下源码
首先我们先来打开mybatis自动配置类MybatisAutoConfiguration找到ConfigurationCustomizer点进去
在这里插入图片描述

之后会看到该类是一个接口,点进去传的参数
在这里插入图片描述
里面会有很多的属性变量
在这里插入图片描述
最后在DruidMyConfig中进行配置绑定

	//实体类属性与数据库字段值做驼峰转换
	@Bean
	public ConfigurationCustomizer configurationCustomizer(){
		return new ConfigurationCustomizer() {
			//重写该接口里的customize方法
			@Override
			public void customize(org.apache.ibatis.session.Configuration configuration) {
				configuration.setMapUnderscoreToCamelCase(true);
			}
		};
	}

那么最后输出结果就正常取到了该字段下的值
当然还可以在.yml配置文件中直接开启
看下源码 找到MybatisConfig可以看到有很多的配置属性
在这里插入图片描述
点开Configuration里面有很多属性,其中驼峰转换也在里面
在这里插入图片描述
application.yml
在这里插入图片描述

springboot-05-crud

springboot-03-crud的基础上 实现了mybatis连接数据库的操作,引入了Employee、Department两张表,进行数据的crud操作。
需要重要掌握的就是,在多对一的情况下 ,对应“一”表的主键在“多”表中做外键,怎么才能让这两个属性关系进行联系,通过在Employee.xml文件中注入sql语句来实现
在这里插入图片描述
Employee.xml

<!--结果嵌套处理-->
    <select id="getAll" resultMap="EmployeeDep">
        select e.id eid,e.lastName elastName,e.email eemail,e.gender egender,e.birth ebirth,d.departmentName ddepartmentName
        from springboot_employee.employee e,springboot_employee.department d where e.did=d.id;
    </select>

    <resultMap id="EmployeeDep" type="Employee">
        <result property="id" column="eid"/>
        <result property="lastName" column="elastName"/>
        <result property="email" column="eemail"/>
        <result property="gender" column="egender"/>
        <result property="birth" column="ebirth"/>
        <association property="department" javaType="Department">
            <result property="departmentName" column="ddepartmentName"/>
        </association>
    </resultMap>

springboot_employee数据库
employee

CREATE TABLE employee(
	`id` int(10) NOT NULL auto_increment,
	name VARCHAR(14) DEFAULT NULL,
	password VALUES(14) DEFAULT NULL,
	email VARCHAR(25) DEFAULT NULL,
	gender INT(10) DEFAULT NULL,
	birth datetime(5) DEFAULT NULL,
	did int (10),
	PRIMARY KEY (id) 
) ENGINE = InnoDB CHARACTER SET = utf8

department

CREATE TABLE department(
	`id` int(10) NOT NULL auto_increment,
	departmentName VARCHAR(20) DEFAULT NULL,
	PRIMARY KEY (id) 
)ENGINE = InnoDB CHARACTER SET = utf8

实现WebMvcConfigurer接口


@Configuration
public class MyMvcConfig implements WebMvcConfigurer {


	@Override
	public void addViewControllers(ViewControllerRegistry registry) {
		// 一般跳转到 首页用自定义跳转请求
		//请求跳转到 主页面 和控制器作用相同
		registry.addViewController("/").setViewName("index");
		registry.addViewController("/main.html").setViewName("dashboard");

	}

	//注册国际化组件 放到spring容器中 才生效
	@Bean
	public LocaleResolver localeResolver() {
		return new MyLocaleResolver();
	}

	//拦截器
	@Override
	public void addInterceptors(InterceptorRegistry registry) {
		registry.addInterceptor(new loginHandlerInterceptor()).addPathPatterns("/**")
				// 拦截...请求 并且放行...请求
				.excludePathPatterns("/", "/user/login", "/css/**", "js/**", "img/**");
	}


	//配置视图解析器
	@Bean
	public InternalResourceViewResolver resourceViewResolver() {
		InternalResourceViewResolver internalResourceViewResolver = new InternalResourceViewResolver();
		//请求视图文件的前缀地址
		internalResourceViewResolver.setPrefix("/WEB-INF/jsp/");
		//请求视图文件的后缀
		internalResourceViewResolver.setSuffix(".jsp");
		return internalResourceViewResolver;
	}


	//注册视图解析器
	@Override
	public void configureViewResolvers(ViewResolverRegistry registry) {
		registry.viewResolver(resourceViewResolver());
	}
}

具体 见代码

springboot-06-security

1、导入依赖

		 <!--thymeleaf-springsecurity5整合包-->
        <dependency>
            <groupId>org.thymeleaf.extras</groupId>
            <artifactId>thymeleaf-extras-springsecurity5</artifactId>
            <version>3.0.4.RELEASE</version>
        </dependency>

        <!--security springboot整合包-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>

        <!--thymeleaf-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>

导入前端页面 如下
在这里插入图片描述
Controller

@Controller
public class LoginController {

	@RequestMapping("/toLogin")
	public String login() {
		return "views/login";
	}

	@RequestMapping("/index")
	public String index() {
		return "index";
	}

	@RequestMapping("/level1/{id}")
	public String level1(@PathVariable("id") Integer id) {
		return "views/level1/" + id;
	}

	@RequestMapping("/level2/{id}")
	public String level2(@PathVariable("id") Integer id) {
		return "views/level2/" + id;
	}

	@RequestMapping("/level3/{id}")
	public String level3(@PathVariable("id") Integer id) {
		return "views/level3/" + id;
	}
}

security 配置文件SecurityConfig
首先继承自WebSecurityConfigurerAdapter类 并
其次实现rotected void configure(HttpSecurity http)授权 和protected void configure(AuthenticationManagerBuilder auth)权限认证策略方法
注意为了保证密码的安全,我们要实现密码加密,其中密码加密的方法很多我们选择BCryptPasswordEncoder()方法操作(ctrl+N 搜索passwordEncoder)
在这里插入图片描述

@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter 

	//授权
	@Override
	protected void configure(HttpSecurity http) throws Exception {
		http.authorizeRequests()
				//全部用户访问
				.mvcMatchers("/").permitAll()
				//... 用户访问... 页面
				.mvcMatchers("/level1/**").hasRole("vip1")
				.mvcMatchers("/level2/**").hasRole("vip2")
				.mvcMatchers("/level3/**").hasRole("vip3");


	    /* 当没有权限时 ,会默认到系统的登录页面
	      定制登录页 loginPage("/toLogin")
		  默认登录的用户名 密码参数分别为 username password 要和表单的name通过设置保持一致
		*/
		http.formLogin().loginPage("/toLogin").usernameParameter("username").passwordParameter("password").loginProcessingUrl("/login");

		//关闭csrf 功能 注销
		http.csrf().disable();

		//注销 跳转路径
		http.logout().logoutSuccessUrl("/index");

		//记住我 原理保存cookie 两周
		//默认参数 remember-me
		http.rememberMe().rememberMeParameter("remember-me");
	}

	//进行权限认证策略

	@Override
	protected void configure(AuthenticationManagerBuilder auth) throws Exception {
		//正常情况下 这些数据应该从数据库中获取
		//密码编码 PasswordEncoder 要对密码进行加密
		auth.inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder())
				.withUser("zz").password(new BCryptPasswordEncoder().encode("123456")).roles("vip1")
				.and()
				.withUser("root").password(new BCryptPasswordEncoder().encode("123456")).roles("vip1","vip2","vip3")
				.and()
				.withUser("guest").password(new BCryptPasswordEncoder().encode("123456")).roles("vip2","vip3");
	}

	/*@Bean
	BCryptPasswordEncoder passwordAuthentication(){
		return new BCryptPasswordEncoder();
	}*/
}

模仿用户权限注销登录
1、添加seciurity-spring依赖

 		<!--thymeleaf-spring整合包-->
        <dependency>
            <groupId>org.thymeleaf.extras</groupId>
            <artifactId>thymeleaf-extras-springsecurity5</artifactId>
            <version>3.0.4.RELEASE</version>
        </dependency>	

2、添加头文件

<html lang="en" xmlns:th="http://www.thymeleaf.org"
      xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity4">

3、更改首页index.html代码
使其达到到当用户没有登录的时候,只出现用户登录的提示,当用户登录完成后,首页只出现用户名和注销的提示;还有当指定用户登录时,只出现该用户有访问权限的页面

<div class="ui secondary menu">
            <a class="item" th:href="@{/index}">首页</a>

            <!--登录-->
            <div class="right menu">
                <!--如果用户 没登录就显示-->
                <div sec:authorize="!isAuthenticated()">
                    <a class="item" th:href="@{/login}">
                        <i class="address card icon"></i> 登录
                    </a>
                </div>


                <!--当用户登录后 显示用户名 和注销提示-->
                <div sec:authorize="isAuthenticated()">
                    <a class="item">
                        用户名: <span sec:authentication="name"></span>
                    </a>
                </div>
                <div sec:authorize="isAuthenticated()">
                    <a class="item" th:href="@{/logout}">
                        <i class="address card icon"></i> 注销
                    </a>
                </div>
                
            </div>
        </div>
<!--根据不同用户 显示权限页面-->
            <div class="column" sec:authorize="hasRole('vip1')">
                <div class="ui raised segment">
                    <div class="ui">
                        <div class="content">
                            <h5 class="content">Level 1</h5>
                            <hr>
                            <div><a th:href="@{/level1/1}"><i class="bullhorn icon"></i> Level-1-1</a></div>
                            <div><a th:href="@{/level1/2}"><i class="bullhorn icon"></i> Level-1-2</a></div>
                            <div><a th:href="@{/level1/3}"><i class="bullhorn icon"></i> Level-1-3</a></div>
                        </div>
                    </div>
                </div>
            </div>
 			<div class="column" sec:authorize="hasRole('vip2')">
                <div class="ui raised segment">
                    <div class="ui">
                        <div class="content">
                            <h5 class="content">Level 2</h5>
                            <hr>
                            <div><a th:href="@{/level2/1}"><i class="bullhorn icon"></i> Level-2-1</a></div>
                            <div><a th:href="@{/level2/2}"><i class="bullhorn icon"></i> Level-2-2</a></div>
                            <div><a th:href="@{/level2/3}"><i class="bullhorn icon"></i> Level-2-3</a></div>
                        </div>
                    </div>
                </div>
            </div>

            <div class="column" sec:authorize="hasRole('vip3')">
                <div class="ui raised segment">
                    <div class="ui">
                        <div class="content">
                            <h5 class="content">Level 3</h5>
                            <hr>
                            <div><a th:href="@{/level3/1}"><i class="bullhorn icon"></i> Level-3-1</a></div>
                            <div><a th:href="@{/level3/2}"><i class="bullhorn icon"></i> Level-3-2</a></div>
                            <div><a th:href="@{/level3/3}"><i class="bullhorn icon"></i> Level-3-3</a></div>
                        </div>
                    </div>
                </div>
            </div>

开启记住我功能实现
用户自定义登录页面,请求路径为"/toLogin"当用户点击自己设置的登录按钮时,会请求到自定义的登录页面,怎么才能让自定义的登录页面和系统的登录的页面请求相同的参数,通过在http.formLogin()后面添加相应的方法来实现

//当没有权限时 ,会默认到系统的登录页面
//定制登录页 loginPage("/toLogin")
// 默认登录的用户名 密码参数分别为 username password 要和表单的name通过设置保持一致
http.formLogin().loginPage("/toLogin").usernameParameter("username").passwordParameter("password").loginProcessingUrl("/login");

注意自定义表单的action

<form th:action="@{/login}" method="post">

并添加记住我

<input type="checkbox" name="remember-me">记住我

以上就是简单的spring-security权限登录功能的实现

springboot-07-hello shiro(maven)

  • Apache Shiro是一个强大且易用的Java安全框架,执行身份验证、授权、密码和会话管理。使用Shiro的易于理解的API,您可以快速、轻松地获得任何应用程序,从最小的移动应用程序到最大的网络和企业应用程序。【百度百科】

  • ApachevShiro注重易用性,因此您可以依靠安全,稳定的身份验证,授权,加密和会话管理。使用Shiro易于理解的API,您可以快速轻松地保护任何应用程序。

  • Apache Shiro是一个功能强大且易于使用的Java安全框架,它为开发人员提供了一种直观,全面的身份验证,授权,加密和会话管理解决方案。

  • 实际上,它可以管理应用程序安全性的所有方面,同时尽可能避免干扰。它建立在可靠的界面驱动设计和OO原则的基础上,可在您可以想象的任何地方实现自定义行为。但是,只要对所有内容都使用合理的默认值,就可以像应用程序安全性一样“轻松”。至少那是我们所追求的。

    Apache Shiro官网

    shiro十分钟快速入门

    1、创建一个maven项目
    在这里插入图片描述
    2、导入依赖

	<dependencies>
        <!--shiro核心类-->
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-core</artifactId>
            <version>1.4.1</version>
        </dependency>

        <!--log4j 日志-->
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>jcl-over-slf4j</artifactId>
            <version>1.7.21</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
            <version>1.7.21</version>
        </dependency>

        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>
    </dependencies>

3、创建log4j.properties

log4j.rootLogger=INFO, stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - %m %n
# General Apache libraries
log4j.logger.org.apache=WARN
# Spring
log4j.logger.org.springframework=WARN
# Default Shiro logging
log4j.logger.org.apache.shiro=INFO
# Disable verbose logging
log4j.logger.org.apache.shiro.util.ThreadContext=WARN
log4j.logger.org.apache.shiro.cache.ehcache.EhCache=WARN

4、创建shiro.ini

[users]
# user 'root' with password 'secret' and the 'admin' role
root = secret, admin
# user 'guest' with the password 'guest' and the 'guest' role
guest = guest, guest
# user 'presidentskroob' with password '12345' ("That's the same combination on
# my luggage!!!" ;)), and role 'president'
presidentskroob = 12345, president
# user 'darkhelmet' with password 'ludicrousspeed' and roles 'darklord' and 'schwartz'
darkhelmet = ludicrousspeed, darklord, schwartz
# user 'lonestarr' with password 'vespa' and roles 'goodguy' and 'schwartz'
lonestarr = vespa, goodguy, schwartz

# -----------------------------------------------------------------------------
# Roles with assigned permissions
#
# Each line conforms to the format defined in the
# org.apache.shiro.realm.text.TextConfigurationRealm#setRoleDefinitions JavaDoc
# -----------------------------------------------------------------------------
[roles]
# 'admin' role has all permissions, indicated by the wildcard '*'
admin = *
# The 'schwartz' role can do anything (*) with any lightsaber:
schwartz = lightsaber:*
# The 'goodguy' role is allowed to 'drive' (action) the winnebago (type) with
# license plate 'eagle5' (instance specific id)
goodguy = winnebago:drive:eagle5

5、创建Quickstart.java

/**
 * @Author 张哲
 * @Date 2020/8/20 19:02
 */
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.config.IniSecurityManagerFactory;

import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.Factory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


/**
 * Simple Quickstart application showing how to use Shiro's API.
 *
 * @since 0.9 RC2
 */
public class Quickstart {

	//日志文件的变量
	private static final transient Logger log = LoggerFactory.getLogger(Quickstart.class);


	public static void main(String[] args) {


		//通过工厂模式 将shiro.ini文件加载进来
		Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro.ini");
		SecurityManager securityManager = factory.getInstance();
		SecurityUtils.setSecurityManager(securityManager);


		// 获取当前的用户对象
		Subject currentUser = SecurityUtils.getSubject();

		// 通过当前用户拿到session
		Session session = currentUser.getSession();
		session.setAttribute("someKey", "aValue");
		String value = (String) session.getAttribute("someKey");
		if (value.equals("aValue")) {
			log.info("Session---->someKey:" + value);
		}

		//判断当前用户是否被认证
		if (!currentUser.isAuthenticated()) {
			//UsernamePasswordToken是一个简单的包含username及password即用户名及密码的登录验证用token
			UsernamePasswordToken token = new UsernamePasswordToken("lonestarr", "vespa");
			//记住我
			token.setRememberMe(true);
			try {
				//登录当前用户 如果登录失败就抛出异常
				currentUser.login(token);
				log.info("用户登录成功");
			} catch (UnknownAccountException uae) {
				log.info("不存在该用户的名字------>[" + token.getPrincipal() + "]");
			} catch (IncorrectCredentialsException ice) {
				log.info("该用户的密码登录错误------>[" + token.getPrincipal() + "]");
			} catch (LockedAccountException lae) {
				log.info("该用户名被锁定");
			}
			// ... catch more exceptions here (maybe custom ones specific to your application?
			catch (AuthenticationException ae) {
				log.info("认证错误");
			}
		}

		//say who they are:
		//print their identifying principal (in this case, a username):
		log.info("User [" + currentUser.getPrincipal() + "] 登录成功");
		log.info("该用户地址--->"+currentUser);

		//test a role:
		if (currentUser.hasRole("schwartz")) {
			log.info("该用户拥有该角色");
		} else {
			log.info("对不起,该用户没有该角色");
		}

		//粗粒度
		if (currentUser.isPermitted("lightsaber:wield")) {
			log.info("该用户拥有该权限");
		} else {
			log.info("sorry,该用户没有改权限");
		}

		//细粒度
		if (currentUser.isPermitted("winnebago:drive:eagle5")) {
			log.info("You are permitted to 'drive' the winnebago with license plate (id) 'eagle5'.  " +
					"Here are the keys - have fun!");
		} else {
			log.info("Sorry, you aren't allowed to drive the 'eagle5' winnebago!");
		}

		//注销
		currentUser.logout();

		//退出
		System.exit(0);
	}
}

springboot-08-shiro(整合springboot)

1、导入spring-shiro依赖

 		
 		.<dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>

        <!--thymeleaf-shiro整合包-->
        <dependency>
            <groupId>com.github.theborakompanioni</groupId>
            <artifactId>thymeleaf-extras-shiro</artifactId>
            <version>2.0.0</version>
        </dependency>

        <!--spring-shiro依赖-->
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring</artifactId>
            <version>1.4.1</version>
        </dependency>

        <!--mysql驱动-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>

        <!--springboot-mybatis-->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.1.1</version>
        </dependency>

        <!--druid-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.21</version>
        </dependency>

        <!--log4j-->
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>

2、ShiroConfig配置类

/*
	subject 用户
	securityManager 管理所有用户
	Realm 连接数据
 */
@Configuration
public class ShiroConfig {

	//ShiroFilterFactoryBean
	@Bean
	public ShiroFilterFactoryBean shiroFilterFactoryBean(@Qualifier("security") DefaultWebSecurityManager securityManager) {
		ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
		//安全管理器
		bean.setSecurityManager(securityManager);

		/*
			anon:无需认证就可以访问
			authc:必须认证了才能访问
			perms: 拥有某个资源的权限才能使用
			user: 拥该用户对象才能使用 记住我
			roles: 拥有某个角色权限 才能使用

		 */
		Map<String, String> filterMap = new LinkedHashMap<>();


		//用户 授权
		filterMap.put("/user/add","perms[user:add]");
		filterMap.put("/user/select","perms[user:select]");
		//登录拦截

		filterMap.put("/user/*", "authc");

		bean.setFilterChainDefinitionMap(filterMap);

		//用户没有权限 去登录页面
		//bean.setLoginUrl("/toLogin");

		//角色没有权限 去未授权页面
		bean.setUnauthorizedUrl("/noautoh");
		return bean;

	}

	//DefaultWebSecurityManager
	@Bean(name = "security")
	public DefaultWebSecurityManager defaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm) {
		DefaultWebSecurityManager manager = new DefaultWebSecurityManager();
		//关联userRealm
		manager.setRealm(userRealm);
		return manager;

	}

	//Realm  需要自定义
	@Bean
	public UserRealm userRealm() {
		return new UserRealm();
	}

	//ShiroDialect 用来整合shiro-thymeleaf
	@Bean
	public ShiroDialect shiroDialect(){
		return new ShiroDialect();
	}
}

3、自定义UserRealm类 进行认证和授权操作

public class UserRealm extends AuthorizingRealm {

	@Autowired
	private UserService userService;

	//授权
	@Override
	protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
		System.out.println("执行了授权");

		SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();

		//拿到当前登录对象的地址
		Subject subject = SecurityUtils.getSubject();

		//拿到当前登录的user对象
		User currectUser = (User)subject.getPrincipal();
		System.out.println(currectUser);

		//设置当前用户的 权限 实际上从数据库中获取用户的权限
		info.addStringPermission(currectUser.getPrerm());

		return info;
	}

	//认证
	@Override
	protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
		System.out.println("执行了认证");

		//定义 用户名 密码
		/*String name = "root";
		String pwd = "123";*/

		//获取控制台 封装到UsernamePasswordToken中的用户名 和密码
		UsernamePasswordToken userToken = (UsernamePasswordToken) authenticationToken;
		User user = userService.getUserByName(userToken.getUsername());
		//判断用户输入的用户名、密码是否和数据库中的相等
		if (user==null){
			//没有这个人 抛出UnknownAccountException异常
			return null;
		}
		//把登录的对象放到session中
		Subject currectUser = SecurityUtils.getSubject();
		Session session = currectUser.getSession();
		session.setAttribute("loginUser",user);


		//加密 MD5
		//密码 验证 shiro来做
		//参数:用户名对象  密码 认证对象
		return new SimpleAuthenticationInfo(user,user.getPwd(),"");
	}
}

4、ShiroController

@Controller
public class ShiroController {

	@RequestMapping({"/", "/index"})
	public String index() {
		return "index";
	}

	@RequestMapping("/user/add")
	public String add() {
		return "/user/add";
	}

	@RequestMapping("/user/select")
	public String select() {
		return "/user/select";
	}

	@RequestMapping("/toLogin")
	public String login() {
		return "login";
	}

	@RequestMapping("/login")
	public String login(@RequestParam("username") String username, @RequestParam("password") String password, Model model) {
		//获取当前用户
		Subject subject = SecurityUtils.getSubject();
		//实际用来 获取前台的参数
		UsernamePasswordToken token = new UsernamePasswordToken(username, password);
		//登录 如果没有抛出异常 说明登录成功
		//异常快捷键ctrl+alt+t
		try {
			//登录成功 返回首页
			subject.login(token);
			return "index";
		} catch (UnknownAccountException e) {
			model.addAttribute("msg", "用户名不存在");
			return "login";
		} catch (IncorrectCredentialsException e) {
			model.addAttribute("msg", "密码错误");
			return "login";
		}
	}

	@RequestMapping("/noautoh")
	@ResponseBody
	public String noauth() {
		return "未授权 无法访问此页面";
	}

	@RequestMapping("/logout")
	public String logout() {
		//注销 移除session 后跳到登录页面
		Subject currectSubject = SecurityUtils.getSubject();
		Session session = currectSubject.getSession();
		session.removeAttribute("loginUser");
		return "login";
	}
}

application.yml

spring:
  datasource:
    username: root
    password: '061298'
    url: jdbc:mysql://localhost:3306/mybaits?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8
    driver-class-name: com.mysql.cj.jdbc.Driver
    ##更换为druid 数据源
    type: com.alibaba.druid.pool.DruidDataSource


    #Spring Boot 默认是不注入这些属性值的,需要自己绑定
    #druid 数据源专有配置
    initialSize: 5
    minIdle: 5
    maxActive: 20
    maxWait: 60000
    timeBetweenEvictionRunsMillis: 60000
    minEvictableIdleTimeMillis: 300000
    validationQuery: SELECT 1 FROM DUAL
    testWhileIdle: true
    testOnBorrow: false
    testOnReturn: false
    poolPreparedStatements: true

    #配置监控统计拦截的filters,stat:监控统计、log4j:日志记录、wall:防御sql注入
    #如果允许时报错  java.lang.ClassNotFoundException: org.apache.log4j.Priority
    #则导入 log4j 依赖即可,Maven 地址:https://mvnrepository.com/artifact/log4j/log4j
    filters: stat,wall,log4j
    maxPoolPreparedStatementPerConnectionSize: 20
    useGlobalDataSourceStat: true
    connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500

mybatis:
  type-aliases-package: com.zz.pojo
  mapper-locations: classpath:mapper/*.xml

index.html

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org"
      xmlns:shiro="http://www.thymeleaf.org/thymeleaf-extras-shiro">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h1>首页</h1>

<div th:if="${session.loginUser}==null">
    <a th:href="@{/toLogin}">登录</a>
</div>
<div th:if="${session.loginUser}!=null">
    <a th:href="@{/logout}">注销</a>
</div>

<div shiro:hasPermission="user:add">
    <a th:href="@{/user/add}">添加</a>
</div>
<div shiro:hasPermission="user:select">
    <a th:href="@{/user/select}">查找</a>
</div>

</body>
</html>

结构图
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值