spring-boot Web开发
配置静态文件
- 可以使用以下方式处理静态资源
webjars : http://localhost:8080/webjars
- resources
- static
- public
http://localhost:8080/
以上文件可直接存放
- 优先级 :resources > static (默认) > public
模板引擎
templates 只能controller 层访问 : 需要模板引擎的支持 需要 Thymeleaf 依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
页面存放在templates文件中
- 首页配置:所有页面的静态资源都需要使用Thymeleaf接管;@{}
加上
xmlns:th="http://www.thymeleaf.org"
配置跳转
@Configuration
public class MyMvcConfig implements WebMvcConfigurer {
@Override
public void addViewControllers(ViewControllerRegistry registry) {
//类似于@RequestMapping("/")
registry.addViewController("/").setViewName("index");
registry.addViewController("/index.html").setViewName("index");
}
}
拦截器
package com.xin.config;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/*登录拦截器*/
public class LoginHandlerInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//获取用户的sessoin
Object loginUser = request.getSession().getAttribute("loginUser");
//判断是否登录
if(loginUser == null){
request.setAttribute("msg","未监测登录,请重新登录");
//转发
request.getRequestDispatcher("/index.html").forward(request,response);
return false;
}else {
return true;
}
}
}
配置拦截器
config 包下
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LoginHandlerInterceptor()).addPathPatterns("/**").excludePathPatterns("/index.html","/","/user/login");
}
addPathPatterns:需要拦截
excludePathPatterns:不需要拦截 注意: 还需要填写css , js 资源等.
Thymeleaf 语法
spring.thymeleaf.cache=false //关闭模板引擎缓存
1. 标签复用
th:fragment="topbar"
需要重复的标签
th:insert="~{dashboard::topbar}"
插入标签
th:replace="~{存放公共标签的地址 :: topbar}"
th:include 和 th:replace都是加载代码块内容,但是还是有所不同
- th:include:加载模板的内容: 读取加载节点的内容(不含节点名称),替换div内容
- th:replace:替换当前标签为模板中的标签,加载的节点会整个替换掉加载他的div
<!-- th:fragment 定义用于加载的块 -->
<span th:fragment="pagination">
the public pagination
</span>
================= th:include 和 th:replace============================
<!-- 加载模板的内容: 读取加载节点的内容(不含节点名称),替换<div>的内容 -->
<div th:include="pagination::pagination">1</div>
<!-- 替换当前标签为模板中的标签: 加载的节点会整个替换掉加载他的<div> -->
<div th:replace="pagination::pagination">2</div>
结果:
<!-- 加载模板的内容: 读取加载节点的内容(不含节点名称),替换<div>的内容 -->
<div> the public pagination</div>
<!-- 替换当前标签为模板中的标签: 加载的节点会整个替换掉加载他的<div> -->
<span> the public pagination</span>
if-- 判断空 例:
<!--如果msg等于null 就不显示-->
<p style="color: red" th:text="${msg}" th:if="${not #strings.isEmpty(msg)}"></p>
restFul 获取参数
@PathVariable("变量")
异常错误页面
templates文件 ==> error文件==> 页面
lombok 实体类注解
- 是一个在Java开发过程中用注解的方式,简化了 JavaBean 的编写,避免了冗余和样板式代码而出现的插件,让编写的类更加简洁。
JDBC配置教程
导入依赖 : 使用idea 创建的时候就可以直接导入 JDBC , MySql Driver
首先配置yaml 配置文件
spring:
datasource:
username: root
password: root
url: jdbc:mysql://localhost:3306/mybatis?useUnicode=true&characterEncoding=utf-8
driver-class-name: com.mysql.jdbc.Driver
Controller 层测试
package com.xin.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
import java.util.Map;
@RestController
public class JDBCController {
@Autowired
JdbcTemplate jdbcTemplate;
//查询全部用户 (这里没有用实体类,用的map代替)
@RequestMapping("/userList")
public List<Map<String,Object>> userList(){
String sql = "select * from user";
List<Map<String, Object>> maps = jdbcTemplate.queryForList(sql);
return maps;
}
//添加一条数据
@RequestMapping("/addUser")
public String addUser(){
String sql = "insert into user(name,pwd) values('小新','123123')";
jdbcTemplate.update(sql);
return "添加成功!";
}
//更新一条数据
@RequestMapping("/updeUser/{id}")
public String updeUser(@PathVariable("id") int id){
String sql = "update user set name=?,pwd=? where id ="+id;
Object[] objects = new Object[2];
objects[0] = "小新2号";
objects[1] = "123456";
jdbcTemplate.update(sql,objects);
return "修改成功!";
}
//删除一条数据
@RequestMapping("/delUser/{id}")
public String delUser(@PathVariable("id") int id){
String sql = "delete from user where id =?";
jdbcTemplate.update(sql,id);
return "删除成功!";
}
}
Druid 数据库连接池
这里没有做笔记,去网上直接找
Mybatis 整合
- 导入相对应的包
- 配置文件
- mybatis配置
- 编写sql
- service层调用dao层
- controller 调用service层
需要整合包
mybatis-spring-boot-starter
配置文件 (application.properties)
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.url=jdbc:mysql://localhost:3306/mybatis?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
#整合mybatis
mybatis.type-aliases-package=com.xin.pojo
mybatis.mapper-locations=classpath:mybatis/mapper/*.xml
实体类 注解
package com.xin.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
private int id;
private String name;
private String pwd;
}
其余步骤和之前mybatis 一样
注意: Mapping包下的类 需要注解
@Mapper
@Repository
public interface UserMapper {
/**
* 查询全部信息
* @return
*/
List<User> selUserList();
/**
* 查询单个
* @param id
* @return
*/
User selUserById(int id);
}
Mapper.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.xin.mapper.UserMapper">
<select id="selUserList" resultType="user">
select * from user
</select>
<select id="selUserById" resultType="user">
select * from user where id = #{id}
</select>
</mapper>
springSecurity(安全)
shiro
shiro主要有三大功能模块
- Subject:主体,一般指用户。
- SecurityManager:安全管理器,管理所有Subject,可以配合内部安全组件。(类似于SpringMVC中的DispatcherServlet)
- Realms:用于进行权限信息的验证,一般需要自己实现。
细分功能
- Authentication:身份认证/登录(账号密码验证)。
- Authorization:授权,即角色或者权限验证。
- Session Manager:会话管理,用户登录后的session相关管理。
- Cryptography:加密,密码加密等。
- Web Support:Web支持,集成Web环境。
- Caching:缓存,用户信息、角色、权限等缓存到如redis等缓存中。
- Concurrency:多线程并发验证,在一个线程中开启另一个线程,可以把权限自动传播过去。
- Testing:测试支持;
- Run As:允许一个用户假装为另一个用户(如果他们允许)的身份进行访问。
- Remember Me:记住我,登录后,下次再来的话不用登录了。
springboot 和shiro + JDBC 整合的步骤
- 创建依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.6.4</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.xin</groupId>
<artifactId>springboot-shiro</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>springboot-shiro</name>
<description>springboot-shiro</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.4.1</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<!-- mybatis-spring-boot-starter -->
<!--自研-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.2.2</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
- 权限对应的实体类
这里不做笔记展示
还要写Mapper 、Service
- 自定义Realm用于查询用户的角色和权限信息并保存到权限管理器:
package com.xin.config;
import com.xin.pojo.User;
import com.xin.service.UserService;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
//自定义的Realm
public class UserRealm extends AuthorizingRealm {
@Autowired
UserService userService;
//授权
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
System.out.println("执行了授权");
//SimpleAuthorizationInfo
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
//拿到当前用户对象
Subject subject = SecurityUtils.getSubject();
User currentUser = (User) subject.getPrincipal(); //拿到User对象 ,强转
//设置当前用户的权限
info.addStringPermission(currentUser.getPerms());
return info;
}
//认证
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken Token) throws AuthenticationException {
System.out.println("执行了认证");
//前端传输 封装的
UsernamePasswordToken token = (UsernamePasswordToken) Token;
//连接数据,取数据
User user = userService.selUserByName(token.getUsername());
if(user==null){
return null;
}
//密码认证, shiro做 ,加密了
//这里的user参数传递 是为了让授权获取到
return new SimpleAuthenticationInfo(user,user.getPwd(),"");
}
}
- ShiroConfig.java
package com.xin.config;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.LinkedHashMap;
import java.util.Map;
@Configuration
public class ShiroConfig {
//3.shiroFilterFactorybean
@Bean
public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("getDefaultWebSecurityManager") DefaultWebSecurityManager defaultWebSecurityManager){
ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
//设置安全管理器
bean.setSecurityManager(defaultWebSecurityManager);
//添加shiro的内置过滤器
/*
anon:无需认证就可以访问
authc:必须认证了才能访问
user:必须拥有 记住我 功能才能用
perms:拥有对某个资源的权限才能访问
role:拥有某个角色权限才能访问
*/
//拦截
Map<String, String> filterMap = new LinkedHashMap<>();
//授权拦截
filterMap.put("/user/add","perms[user:add]");
filterMap.put("/user/upda","perms[user:upda]");
filterMap.put("/user/*","authc");//user下页面必须要认证后才能拿访问
bean.setFilterChainDefinitionMap(filterMap);
//设置登录页面的跳转
bean.setLoginUrl("/toLogin");
//设置没有权限跳转页面
bean.setUnauthorizedUrl("/perms");
return bean;
}
//2.DafaultWebSecurityManger
@Bean
public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm){
DefaultWebSecurityManager SecurityManager = new DefaultWebSecurityManager();
//关联userRealm
SecurityManager.setRealm(userRealm);
return SecurityManager;
}
//1.创建 realm 对象,需要自定义
@Bean
public UserRealm userRealm(){
return new UserRealm();
}
}
- Controller
package com.xin.controller;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
public class MyController {
@RequestMapping({"/","/index"})
public String toindex(Model model){
model.addAttribute("msg","Hello,shiro");
return "index";
}
@RequestMapping("user/add")
public String add(){
return "user/add";
}
@RequestMapping("user/upda")
public String upda(){
return "user/upda";
}
@RequestMapping("/toLogin")
public String toLogin(){
return "login";
}
@RequestMapping("login")
public String login(String username,String password,Model model){
//获取当前用户
Subject subject = SecurityUtils.getSubject();
//封装用户的登录数据
UsernamePasswordToken token = new UsernamePasswordToken(username, password);
try {
//执行登录方法, 如果没有异常就直接登录
subject.login(token);
return "index";
}catch (UnknownAccountException e){
model.addAttribute("msg","用户名不存在");
return "login";
}catch (IncorrectCredentialsException e){
model.addAttribute("msg","密码错误!");
return "login";
}
}
@RequestMapping("/perms")
@ResponseBody
public String perms(){
return "对不起,你没有访问权限";
}
}
- 目录结构图
shiro 整合 Thymeleaf
导入整合依赖
<dependency>
<groupId>com.github.theborakompanioni</groupId>
<artifactId>thymeleaf-extras-shiro</artifactId>
<version>2.1.0</version>
</dependency>
ShiroConfig 中配置整合
//整合shiro : 用来整合shiro 和 thymeleaf
@Bean
public ShiroDialect getShiroDialect(){
return new ShiroDialect();
}
html页面中加上
xmlns:shiro="http://www.thymeleaf.org/thymeleaf-extras-shiro"
前端代码
<!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>
</head>
<body>
<h1>首页</h1>
<div th:if="${session.loginUser==null}">
<a th:href="@{/toLogin}">登录</a>
</div>
<p th:text="${msg}"></p>
<hr>
<div shiro:hasPermission="user:add">
<a th:href="@{/user/add}">add</a>
</div>
<div shiro:hasPermission="user:upda">
<a th:href="@{user/upda}">upda</a>
</div>
</body>
</html>
评论 (0)