springboot常用注解:
https://github.com/mxg133/learnforSpringBoot
注解 | 解释 |
---|---|
@SpringBootApplication | 来标注一个主程序类,说明这是一个springboot应用。 |
@RequestMapping(“/hello”) | 接收来自于浏览器的hello请求,给出外界访问方法的路径,或者说触发路径 ,触发条件。 |
@RequestBody | @RequestBody除了把return的结果变成JSON对象返回,还可以把前端传输过来的json数据自动装配成后端可操作的map对象或自定义对象。 |
@ResponseBody | 用@ResponseBody标记Controller类中的方法。把return的结果变成JSON对象返回,把类的方法返回的数据写给浏览器。(如果没有这个注解,这个方法只能返回要跳转的路径即跳转的html/JSP页面。有这个注解,可以不跳转页面,只返回JSON数据)。 |
@Controller | @Controller标识的类,该类代表控制器类(控制层/表现层)。 |
@RestController | 是==@Controller和@ResponseBody==的结合。 |
@Repository | 作用于数据访问层。 |
@Service | 作用于业务逻辑层。 |
@SpringBootConfiguration | SpringBoot的配置类,标注在某个类上,表明这是一个SpringBoot的配置类。 |
@EnableAutoConfiguration | 开启自动配置。 |
@AutoConfigurationPackage | 自动配置包,将主配置类(@SpringBootApplication标注的类)的所在包及所有子包里的所有组件扫描到spring容器里。 |
@Import() | 给容器导入组件。 |
@ConfigurationProperties(prefix=“person”) | 将配置文件中配置的每一个属性,映射到这个组件中,告诉springboot将本类中的所有属性和配置文件中相关的配置进行绑定;prefix前缀,将配置文件中的"person"下的属性映射进来。 |
@Component | 把该组件注入springboot容器。作用于实体类或者工具类。 |
@PropertySource({“classpath:xxx.properties”}) | 加载指定的properties配置文件。 |
@Configuration | 指明当前类是一个配置类,就是用来替代之前的spring配置文件,可以和@Bean搭配使用。 |
@EnableWebMvc | 加上这个注解,将使所有SpringMVC的自动配置失效,使用自己的配置。 |
@Async | 告诉Spring这是一个异步方法 |
@RequestMapping | @RequestMapping可以指定GET、POST请求方式 |
@GetMapping | @GetMapping等价于@RequestMapping的GET请求方式 |
@ImportResource | springboot默认使用Java配置,但也可以使用xml配置,只需通过该注解引入一个xml配置。 |
@PathVariable
@PathVariable绑定URI模板变量值
@PathVariable是用来获得请求url中的动态参数的
@PathVariable用于将请求URL中的模板变量映射到功能处理方法的参数上。//配置url和方法的一个关系
@RequestMapping(“item/{itemId}”)
@RequestMapping 来映射请求,也就是通过它来指定控制器可以处理哪些URL请求,类似于struts的action请求。
@responsebody 表示该方法的返回结果直接写入HTTP responseBody中一般在异步获取数据时使用,在使用@RequestMapping后,返回值通常解析为跳转路径,加上@responsebody后返回结果不会被解析为跳转路径,而是直接写入HTTP responseBody中。比如异步获取json数据,加上@responsebody后,会直接返回json数据。
@Pathvariable 注解绑定它传过来的值到方法的参数上用于将请求URL中的模板变量映射到功能处理方法的参数上,即取出uri模板中的变量作为参数
@RequestMapping("/zyh/{type}")
public String zyh(@PathVariable(value = "type") int type) throws UnsupportedEncodingException {
String url = "http://wx.diyfintech.com/zyhMain/" + type;
if (type != 1 && type != 2) {
throw new IllegalArgumentException("参数错误");
}
String encodeUrl = URLEncoder.encode(url, "utf-8");
String redirectUrl = MessageFormat.format(OAUTH_URL, WxConfig.zyhAppId, encodeUrl, "snsapi_userinfo", UUID.randomUUID().toString().replace("-", ""));
return "redirect:" + redirectUrl;m
}
在SpringMVC后台控制层获取参数的方式主要有两种:
一种是request.getParameter(“name”),另外一种是用注解@RequestParam直接获取
这里主要讲这个注解 @RequestParam
value:参数名字,即入参的请求参数名字,如username表示请求的参数区中的名字为username的参数的值将传入;
required:是否必须,默认是true,表示请求中一定要有相应的参数,否则将报404错误码;
defaultValue:默认值,表示如果请求中没有同名参数时的默认值,例如:
public List getItemTreeNode(@RequestParam(value=”id”,defaultValue=”0”)long parentId)
@Controller
@RequestMapping("/wx")
public class WxController {
@Autowired
private WxService wxService;
private static final Log log= LogFactory.getLog(WxController.class);
@RequestMapping(value = "/service",method = RequestMethod.GET)
public void acceptWxValid(@RequestParam String signature, @RequestParam String timestamp, @RequestParam String nonce,
@RequestParam String echostr, HttpServletResponse response) throws IOException {
PrintWriter out = response.getWriter();
if (SignUtil.checkSignature(signature, timestamp, nonce)) {
out.print(echostr);
}else
out.print("fail");
out.flush();
out.close();
}
@ConfigurationProperties | @Value() | |
---|---|---|
功能 | 批量注入配置文件中的属性 | 一个个指定 |
@RequestParam
(1)不加@RequestParam前端的参数名需要和后端控制器的变量名保持一致才能生效
(2)不加@RequestParam参数为非必传,加@RequestParam写法参数为必传。但@RequestParam可以通过@RequestParam(required = false)设置为非必传。
(3)@RequestParam可以通过@RequestParam(“userId”)或者@RequestParam(value = “userId”)指定传入的参数名。
(4)@RequestParam可以通过@RequestParam(defaultValue = “0”)指定参数默认值
(5)如果接口除了前端调用还有后端RPC调用,则不能省略@RequestParam,否则RPC会找不到参数报错
(6)Get请求访问时:
- 不加@RequestParam注解:url可带参数也可不带参数,输入 localhost:8080/list1 以及 localhost:8080/list1?userId=xxx 方法都能执行
- 加@RequestParam注解:url必须带有参数。也就是说你直接输入localhost:8080/list2 会报错,不会执行方法。只能输入localhost:8080/list2?userId=xxx 才能执行相应的方法
Mysql数据库连接配置:
数据库连接application.properties:
spring.datasource.username=root spring.datasource.password=123456 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
数据库连接application.yml:
spring: datasource: url: jdbc:mysql://localhost:3306/rate?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8 username: root password: 123456 driver-class-name: com.mysql.jdbc.Driver jpa: # 显示sql语句 show-sql: true properties: hibernate: # 格式化sql语句 format_sql: true server: port: 8080
Thymeleaf语法
依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
thymeleaf 命名空间:
xmlns:th="http://www.thymeleaf.org"
xmlns:sec="http://www.thymeleaf.org/extras/spring-security"
xmlns:shiro="http://www.pollix.at/thymeleaf/shiro"
<html lang="en" xmlns:th="http://www.thymeleaf.org"
xmlns:sec="http://www.thymeleaf.org/extras/spring-security"
xmlns:shiro="http://www.pollix.at/thymeleaf/shiro">
${...}:获取变量值;
th:object="${}" 来获取对象信息
*{...}:选择变量表达式,在功能上和${...}是一样的;
补充:配合${...}使用,用*{}代替${}获取的对象
示例:
<div th:object="${session.user}"> #获取对象user
<p>Name: <span th:text="*{firstName}">Sebastian</span>.</p> #通过*{}获取对象user的firstName
<p>Surname: <span th:text="*{lastName}">Pepper</span>.</p>
<p>Nationality: <span th:text="*{nationality}">Saturn</span>.</p>
</div>
#{...}:获取国际化内容(中英文切换)
@{...}:定义URL链接表达式
访问这个链接时:<!-- Will produce 'http://localhost:8080/gtvg/order/details?orderId=3' (plus rewriting) -->
通过:<a href="details.html" th:href="@{http://localhost:8080/gtvg/order/details(orderId=${o.id})}">view</a>
~{...}:片段引用表达式
#表单里面可以有三种方式来获取对象属性
使用 th:value="*{属性名}"
使用 th:value="${对象.属性名}",对象指的是上面使用 th:object 获取的对象
使用 th:value="${对象.get方法}",对象指的是上面使用 th:object 获取的对象
常用的标签操作
标签 | 功能 | 例子 |
---|---|---|
th:value | 给属性赋值 | |
th:style | 设置样式 | |
th:onclick | 点击事件 | th:onclick="'getInfo()'" |
th:if | 条件判断 | th:if="${not #strings.isEmpty(msg)}" |
th:href | 超链接 | th:href="@{/index.html(l=zh_CN)}" |
th:unless | 条件判断和th:if 相反 | |
th:switch | 配合th:case | |
th:case | 配合th:switch | |
th:src | 地址引入 | th:src="@{/img/bootstrap-solid.svg}" |
th:action | 表单提交的地址 | th:action="@{/user/login}" |
整合JDBC
jdbc增删改查
JdbcController:
@RestController
public class JdbcController {
@Autowired
JdbcTemplate jdbcTemplate;
//查询数据库的所有信息 万能Map
@GetMapping("/userList")
public List<Map<String,Object>> userList(){
String sql="select * from user";
List<Map<String, Object>> List_maps = jdbcTemplate.queryForList(sql);
return List_maps;
}
@GetMapping("/addUser")
public String addUser(){
String sql="insert into mybatis.user(id,name,pwd) value (1,'小龙','345678')";
jdbcTemplate.update(sql);
return "update-ok";
}
@GetMapping("/updateUser/{id}")
public String updateUser(@PathVariable("id") int id){
String sql="update mybatis.user set name=?,pwd=? where id="+id;
//封装
Object[] objects = new Object[2];
objects[0]="anny";
objects[1]="121212";
jdbcTemplate.update(sql,objects);
return "update-ok";
}
@GetMapping("/deletUser/{id}")
public String deletUser(@PathVariable("id")int id){
String sql="delete from mybatis.user where id=?";
jdbcTemplate.update(sql,id);
return "deletUser-ok";
}
application.yml:
Spring:
datasource:
username: root
password: 123456
url: jdbc:mysql://localhost:3306/mybatis?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8
driver-calss-name: com.mysql.jdbc.Driver
type: com.alibaba.druid.pool.DruidDataSource
整合Druid自定义数据源
是阿里巴巴开源平台上的一个数据库连接池实现,结合了C3p0、DBCP、PROXOOL等DB池的优点,同时加入了日志监控。
Druid依赖<1.2.8>:
<!-- https://mvnrepository.com/artifact/com.alibaba/druid -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.2.8</version>
</dependency>
log4j依赖:
<!-- https://mvnrepository.com/artifact/log4j/log4j -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
application.yml:
#SpringBoot默认是不注入这些的,需要自己绑定
#druid数据源专有配置
Spring:
datasource:
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:监控统计、log4j:日志记录、wall:防御sql注入
#如果允许报错,java.lang.ClassNotFoundException: org.apache.Log4j.Properity
#则导入log4j 依赖就行
filters: stat,wall,log4j
maxPoolPreparedStatementPerConnectionSize: 20
useGlobalDataSourceStat: true
connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500
DruidConfig:
@Configuration
public class DruidConfig {
@ConfigurationProperties(prefix = "spring.datasource")//绑定application.yml中的Spring: datasource:
@Bean
public DataSource druidDataSource() {
return new DruidDataSource();
}
//后台监控
@Bean
public ServletRegistrationBean StatViewServlet() {
ServletRegistrationBean<StatViewServlet> bean = new ServletRegistrationBean<>(new StatViewServlet(), "/druid/*");
//后台需要有人登录,账号密码配置
HashMap<String, String> initParameters = new HashMap<>();
//增加配置
initParameters.put("loginUsername", "admin");//登录key 是固定的loginUsername loginPassword
initParameters.put("loginPassword", "123456");
//允许谁可以访问
initParameters.put("allow", "");//所有人可访问
//initParameters.put("allow", "localhost");//本机可访问
//禁止谁能访问 initParameters.put("mest","192.168.11.123");
bean.setInitParameters(initParameters);//设置初始化参数
return bean;
}
//filter过滤
@Bean
public FilterRegistrationBean webStatFilter() {
FilterRegistrationBean bean = new FilterRegistrationBean();
bean.setFilter(new WebStatFilter());
//可以过滤哪些请求
Map<String, String> initParameters = new HashMap<>();
//这些东西不进行统计
initParameters.put("exclusions", "*.js,*.css,/druid/*");
bean.setInitParameters(initParameters);
return bean;
}
}
启动项目后访问http://localhost:8080/druid
:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-APwqOhWj-1673610088513)(…/springboot随堂笔记/assets/image-20220822201855299.png)]
整合Mybatis
service层主要做的是业务逻辑处理的工作,dao层里面做的是和数据库连接的工作。
service层调用dao层的功能,也就是将dao层的类作为service层类的私有成员变量。
- 导入包
mybatis依赖包:
<!-- https://mvnrepository.com/artifact/org.mybatis.spring.boot/mybatis-spring-boot-starter -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.2.2</version>
</dependency>
- 配置文件
spring.datasource.username=root
spring.datasource.password=123456
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
mybatis.type-aliases-package=com.mest.pojo
mybatis.mapper-locations=classpath:mybatis/mapper/*.xml
- 编写sql
<?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.mest.mapper.UserMapper">
<select id="queryUserList" resultType="User">
select * from user
</select>
<select id="queryUserByid" resultType="User">
select * from user where id=#{id}
</select>
<insert id="addUser" parameterType="User">
insert into user (id,name ,pwd) values (#{id},#{name},#{pwd})
</insert>
<update id="updateUser" parameterType="User">
update user set name =#{name},pwd=#{pwd} where id=#{id}
</update>
<delete id="deleteUser" parameterType="int">
delete from user where id=#{id}
</delete>
</mapper>
-
Service调用dao层
-
Controller调用service层
SpringSecurity(安全框架)
web开发中常用的安全功能,过滤器,拦截器
SpringSecurity主要目标是认证和授权(访问控制)
security依赖:
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-security -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
<version>2.6.8</version>
</dependency>
securityConfig配置:
@EnableWebSecurity
public class securityConfig extends WebSecurityConfigurerAdapter {
//授权
@Override
protected void configure(HttpSecurity http) throws Exception {
//首页所有人可以访问,功能页只有有权限的人才能访问
//请求授权的规则
http.authorizeRequests().antMatchers("/").permitAll()
.antMatchers("/level1/**").hasRole("vip1")
.antMatchers("/level2/**").hasRole("vip2")
.antMatchers("/level3/**").hasRole("vip3");
//没有权限跳到登录页,需要开启登录的页面
//定制登录页面
http.formLogin().loginPage("/toLogin").loginProcessingUrl("/login");
//http.formLogin().loginPage("/toLogin");
//注销
//防止网站攻击
http.csrf().disable();//关闭csrf功能
http.logout().logoutSuccessUrl("/");
//开启记住我功能 cookie 默认保存两周,自定义接收前端的参数
http.rememberMe().rememberMeParameter("remember");
}
//认证
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
//这些数据正常应该从数据库中读
//密码编码错误:There was an unexpected error (type=Internal Server Error, status=500).
auth.inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder())
.withUser("mest").password(new BCryptPasswordEncoder().encode("123456")).roles("vip1","vip2")
.and().withUser("saisai").password(new BCryptPasswordEncoder().encode("123456")).roles("vip1","vip2","vip3")
.and().withUser("honey").password(new BCryptPasswordEncoder().encode("123456")).roles("vip1");
}
Shiro
有哪些功能:
Authentication:身份验证、登录、验证用户是否拥有相应的身份。
Authorization:授权,即权限验证。判断用户能进行什么操作。
Session Manager:会话管理,即用户登录就是第一次会话,在没有退出之前,所有信息都保存在会话中。
Remember me:记住我。
…
整合shiro:
项目结构:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uooB0RF6-1673610088515)(assets/image-20220824103551304.png)]
-
pom.xml:
<?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.mest</groupId> <artifactId>shiro</artifactId> <version>0.0.1-SNAPSHOT</version> <name>shiro</name> <description>Demo project for Spring Boot</description> <properties> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!--Subject 用户 SecurityManager 管理所有用户 Realm 连接所有数据 --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.17</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.1.12</version> </dependency> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>2.1.0</version> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.16.10</version> </dependency> <!-- shiro thymeleaf整合的包--> <dependency> <groupId>com.github.theborakompanioni</groupId> <artifactId>thymeleaf-extras-shiro</artifactId> <version>2.0.0</version> </dependency> <!-- shiro整合spring的包--> <!-- https://mvnrepository.com/artifact/org.apache.shiro/shiro-spring --> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring</artifactId> <version>1.4.1</version> </dependency> <!--thymeleaf模板--> <dependency> <groupId>org.thymeleaf</groupId> <artifactId>thymeleaf-spring5</artifactId> </dependency> <dependency> <groupId>org.thymeleaf.extras</groupId> <artifactId>thymeleaf-extras-java8time</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>
-
ShiroConfiger配置类:
@Configuration
public class ShiroConfiger {
//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/update", "perms[user:update]");
// filterMap.put("/user/add","authc");
// filterMap.put("/user/update","authc");
filterMap.put("/user/*", "authc");
bean.setFilterChainDefinitionMap(filterMap);
//设置登录的请求
bean.setLoginUrl("/toLogin");
//未授权页面
bean.setUnauthorizedUrl("/noauth");
return bean;
}
//DefaultWebSecurityManager
@Bean
public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm) {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
//关联UserRealm
securityManager.setRealm(userRealm);
return securityManager;
}
//创建realm对象,需要自定义类
@Bean
public UserRealm userRealm() {
return new UserRealm();
}
@Bean
//整合shiroDialect: 用来整合shiro和thymeleaf
public ShiroDialect getShiroDialect() {
return new ShiroDialect();
}
}
- 自定义UserRealm类:
//自定义realm
public class UserRealm extends AuthorizingRealm {
@Autowired
UserService userService;
// 授权
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
// info.addStringPermission("user:add");默认会走,开启后全部授权,
//当拿到当前登录的这个对象
Subject subject= SecurityUtils.getSubject();
User currentUser = (User) subject.getPrincipal();//拿到user对象
//设置当前用户的权限
info.addStringPermission(currentUser.getPerms());
return info;
}
// 认证
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
// //用户名,密码
// String username="root";
// String password="123456";
//连接真实数据库
UsernamePasswordToken userToken = (UsernamePasswordToken) authenticationToken;
// if(!userToken.getUsername().equals(username)){
// return null;//抛出异常
// }
User user = userService.queryUserByName(userToken.getUsername());
if(user==null){//没有这个人
return null;
}
Subject currentSubject = SecurityUtils.getSubject();
Session session = currentSubject.getSession();
session.setAttribute("loginUser",user);
return new SimpleAuthenticationInfo(user,user.getPwd(),"");//把user对象放入
}
}
- MyController:
@Controller
public class MyController {
@GetMapping({"/", "/index"})
public String toIndex(Model model) {
model.addAttribute("msg", "hello,shiro");
return "index";
}
@RequestMapping("/user/add")
public String add() {
return "user/add";
}
@RequestMapping("/user/update")
public String update() {
return "user/update";
}
@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);//执行登录的方法 如果没有异常就ok
return "index";
} catch (UnknownAccountException e) {
model.addAttribute("msg", "用户名错误");
return "login";
} catch (IncorrectCredentialsException e) {
model.addAttribute("msg", "密码错误");
return "login";
}
}
@RequestMapping("/noauth")
@ResponseBody
public String unauthroized() {
return "未授权页面";
}
}
-
mapper层:
@Repository
@Mapper
public interface UserMapper {public User queryUserByName(String name);
}
-
实体类pojo:
@Data @AllArgsConstructor @NoArgsConstructor public class User { private int id; private String name; private String pwd; private String perms;//权限 }
-
server层:
//UserService public interface UserService { public User queryUserByName(String name); }
-
UserServiceImpl实现类:
@Service
public class UserServiceImpl implements UserService{
@Autowired
UserMapper userMapper;
@Override
public User queryUserByName(String name) {
return userMapper.queryUserByName(name);
}
}
- 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.mest.mapper.UserMapper">
<select id="queryUserByName" parameterType="String" resultType="User">
select * from mybatis.user where name = #{name}
</select>
</mapper>
- application.yml数据库连接:
spring:
datasource:
username: root
password: 123456
url: jdbc:mysql://localhost:3306/mybatis?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8
driver-class-name: com.mysql.cj.jdbc.Driver
type: com.alibaba.druid.pool.DruidDataSource
#SpringBoot默认是不注入这些的,需要自己绑定
#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.Properity
#则导入log4j 依赖就行
filters: stat,wall,log4j
maxPoolPreparedStatementPerConnectionSize: 20
useGlobalDataSourceStat: true
connectionoProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500
- application.properties:
mybatis.type-aliases-package=com.mest.pojo
mybatis.mapper-locations=classpath:mapper/*.xml
- 前端页面
发送邮件
- 导入发送邮件的依赖
<!--邮件发送-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/com.sun.mail/jakarta.mail -->
<dependency>
<groupId>com.sun.mail</groupId>
<artifactId>jakarta.mail</artifactId>
<version>1.6.5</version>
</dependency>
- 配置application.properties文件
[email protected]
spring.mail.password=wvwidyvmstzadhah # qq邮箱pop3令牌
spring.mail.host=smtp.qq.com
#开启加密验证
spring.mail.properties.mail.smtp.ssl.enabled=true
- 实现:
@SpringBootTest
class TaskApplicationTests {
@Autowired
JavaMailSenderImpl mailSender;
@Test
void contextLoads() {
//简单的邮件
SimpleMailMessage simpleMailMessage = new SimpleMailMessage();
simpleMailMessage.setSubject("通知");//主题
simpleMailMessage.setText("关于延期开学通知");//文本
simpleMailMessage.setFrom("[email protected]");
simpleMailMessage.setTo("[email protected]");
mailSender.send(simpleMailMessage);
}
//复杂的邮件
@Test
void contextLoads2() throws MessagingException {
MimeMessage mimeMessage = mailSender.createMimeMessage();
//组装
MimeMessageHelper helper = new MimeMessageHelper(mimeMessage,true);
//正文
helper.setSubject("网易夏日摸鱼");
helper.setText("<p style='color:blue'>网易邮箱摸鱼大片爆笑热映,加班?大饼?\n 漏漏漏!只要我摸得够多,内卷就追不上我!</p>",true);
//附件
helper.addAttachment("1.jpg",new File("C:\\Users\\缪晟\\Desktop\\1.jpg"));
helper.setFrom("[email protected]");
helper.setTo("[email protected]");
mailSender.send(mimeMessage);
}
//封装发送邮件的方法
/*
tf:true or false
subject:主题
text:正文
* */
public void sendMail(Boolean tf,String subject,String text) throws MessagingException {
MimeMessage mimeMessage = mailSender.createMimeMessage();
//组装
MimeMessageHelper helper = new MimeMessageHelper(mimeMessage,tf);
//正文
helper.setSubject(subject);
helper.setText("<p style='color:blue'>"+text+"</p>",tf);
//附件
helper.addAttachment("1.jpg",new File("C:\\Users\\缪晟\\Desktop\\1.jpg"));
helper.setFrom("[email protected]");
helper.setTo("[email protected]");
mailSender.send(mimeMessage);
}
}
定时执行任务
https://www.bejson.com/ 网络,前端,后端,加解密,转换,数据处理,表达式网站
@Service
public class ScheduledService {
//在一个特定的时间执行
//cron()表达式
/*
//秒 分 时 日 月 星期
30 15 10 * * ? 每天的10点15分30秒执行
0 0/5 10,18 * * ? 每天的10点和18点,每隔5分钟执行执行一次
0 15 10 ? * 1-6 每个月的星期1-6 的10点15分执行一次
0 15 10 L * ? 每个月的最后一天的10点15分执行一次
0/2 * * * * ? 每隔两秒执行一次
* */
//秒 分 时 日 月 星期
@Scheduled(cron = "0/2 * * * * ?")
public void hello(){
System.out.println("hello,你被执行了");
}
}
SpringBoot整合Redis
- 引入redis:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
- 配置application.properties:
#SpringBoot所有的配置类,都有一个自动配置类RedisAutoConfig
#自动配置类都会绑定一个properties 配置文件 RedisProperties
spring.redis.host=127.0.0.1
spring.redis.port=6379
- 创建User对象
@Component
@Data
@AllArgsConstructor
@NoArgsConstructor
//implements Serializable实现序列化
public class User implements Serializable {
private String username;
private Integer age;
}
- 测试存值取值
@SpringBootTest
class SpringbootRedisApplicationTests {
//引入RedisTemplate模板
@Autowired
@Qualifier("redisTemplate")
private RedisTemplate redisTemplate;
@Test
void contextLoads() {
//redisTemplate 操作不同的数据类型 api和我们的指令命令是一致的
//opsForValue 操作字符串 类似String
//opsForList 操作List 类似List
//opsForSet
//opsForHash
//opsForGeo
//除了基本的操作 我们常用的方法也可以通过redisTemplate来操作 比如事务 和CRUD
//获取redis的连接对象
// RedisConnection connection= redisTemplate.getConnectionFactory().getConnection();
// connection.flushAll();
// connection.flushDb();
redisTemplate.opsForValue().set("mykey", "hellomest");
System.err.println(redisTemplate.opsForValue().get("mykey"));
}
//测试存放user对象(User对象未实例化)
@Test
public void testRedis() throws JsonProcessingException {
User user = new User("redis_zhangsan", 12);
String jsonUser = new ObjectMapper().writeValueAsString(user);
redisTemplate.opsForValue().set("user", jsonUser);//key,value
System.err.println(redisTemplate.opsForValue().get("user"));
}
//测试存放user对象(User对象被实例化)
@Test
public void testRedis2() throws JsonProcessingException {
User user = new User("redis_lisi", 11);
redisTemplate.opsForValue().set("user", user);//key,value
System.err.println(redisTemplate.opsForValue().get("user"));
}
//使用RedisUtils工具类
@Autowired
private RedisUtil redisUtil;
@Test
public void testRedisUtil() {
redisUtil.set("username","hello");
System.out.println(redisUtil.get("username"));
}
}
RedisTemplate模板
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
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.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
/**
* 定义RedisTemplate模板
*/
@Configuration
public class RedisConfig {
@Bean
@SuppressWarnings("all")
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
// 连接工厂
redisTemplate.setConnectionFactory(redisConnectionFactory);
// Json序列化配置
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
// String序列化配置
StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
// key采用String的序列化方式
redisTemplate.setKeySerializer(stringRedisSerializer);
// hash的key也采用String的序列化方式
redisTemplate.setHashKeySerializer(stringRedisSerializer);
// value序列化方式采用jackson
redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
// hash的value序列化方式采用jackson
redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);
redisTemplate.afterPropertiesSet();
return redisTemplate;
}
}
在SpringbootRedisApplicationTests中使用RedisTemplate模板:
@Autowired
@Qualifier("redisTemplate")
private RedisTemplate redisTemplate;
@Test
public void testRedis2() throws JsonProcessingException {
User user = new User("redis_lisi", 11);
redisTemplate.opsForValue().set("user", user);//key,value
System.err.println(redisTemplate.opsForValue().get("user"));
}
RedisUtils工具类
封装RedisUtils工具类,避免使用原生api的方式编写代码,直接使用:
package com.mest.utils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
@Component
public final class RedisUtil {
@Autowired
private RedisTemplate<String, Object> redisTemplate;
// =============================common============================
/**
* 指定缓存失效时间
* @param key 键
* @param time 时间(秒)
*/
public boolean expire(String key, long time) {
try {
if (time > 0) {
redisTemplate.expire(key, time, TimeUnit.SECONDS);
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 根据key 获取过期时间
* @param key 键 不能为null
* @return 时间(秒) 返回0代表为永久有效
*/
public long getExpire(String key) {
return redisTemplate.getExpire(key, TimeUnit.SECONDS);
}
/**
* 判断key是否存在
* @param key 键
* @return true 存在 false不存在
*/
public boolean hasKey(String key) {
try {
return redisTemplate.hasKey(key);
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 删除缓存
* @param key 可以传一个值 或多个
*/
@SuppressWarnings("unchecked")
public void del(String... key) {
if (key != null && key.length > 0) {
if (key.length == 1) {
redisTemplate.delete(key[0]);
} else {
redisTemplate.delete(CollectionUtils.arrayToList(key));
}
}
}
// ============================String=============================
/**
* 普通缓存获取
* @param key 键
* @return 值
*/
public Object get(String key) {
return key == null ? null : redisTemplate.opsForValue().get(key);
}
/**
* 普通缓存放入
* @param key 键
* @param value 值
* @return true成功 false失败
*/
public boolean set(String key, Object value) {
try {
redisTemplate.opsForValue().set(key, value);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 普通缓存放入并设置时间
* @param key 键
* @param value 值
* @param time 时间(秒) time要大于0 如果time小于等于0 将设置无限期
* @return true成功 false 失败
*/
public boolean set(String key, Object value, long time) {
try {
if (time > 0) {
redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS);
} else {
set(key, value);
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 递增
* @param key 键
* @param delta 要增加几(大于0)
*/
public long incr(String key, long delta) {
if (delta < 0) {
throw new RuntimeException("递增因子必须大于0");
}
return redisTemplate.opsForValue().increment(key, delta);
}
/**
* 递减
* @param key 键
* @param delta 要减少几(小于0)
*/
public long decr(String key, long delta) {
if (delta < 0) {
throw new RuntimeException("递减因子必须大于0");
}
return redisTemplate.opsForValue().increment(key, -delta);
}
// ================================Map=================================
/**
* HashGet
* @param key 键 不能为null
* @param item 项 不能为null
*/
public Object hget(String key, String item) {
return redisTemplate.opsForHash().get(key, item);
}
/**
* 获取hashKey对应的所有键值
* @param key 键
* @return 对应的多个键值
*/
public Map<Object, Object> hmget(String key) {
return redisTemplate.opsForHash().entries(key);
}
/**
* HashSet
* @param key 键
* @param map 对应多个键值
*/
public boolean hmset(String key, Map<String, Object> map) {
try {
redisTemplate.opsForHash().putAll(key, map);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* HashSet 并设置时间
* @param key 键
* @param map 对应多个键值
* @param time 时间(秒)
* @return true成功 false失败
*/
public boolean hmset(String key, Map<String, Object> map, long time) {
try {
redisTemplate.opsForHash().putAll(key, map);
if (time > 0) {
expire(key, time);
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 向一张hash表中放入数据,如果不存在将创建
*
* @param key 键
* @param item 项
* @param value 值
* @return true 成功 false失败
*/
public boolean hset(String key, String item, Object value) {
try {
redisTemplate.opsForHash().put(key, item, value);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 向一张hash表中放入数据,如果不存在将创建
*
* @param key 键
* @param item 项
* @param value 值
* @param time 时间(秒) 注意:如果已存在的hash表有时间,这里将会替换原有的时间
* @return true 成功 false失败
*/
public boolean hset(String key, String item, Object value, long time) {
try {
redisTemplate.opsForHash().put(key, item, value);
if (time > 0) {
expire(key, time);
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 删除hash表中的值
*
* @param key 键 不能为null
* @param item 项 可以使多个 不能为null
*/
public void hdel(String key, Object... item) {
redisTemplate.opsForHash().delete(key, item);
}
/**
* 判断hash表中是否有该项的值
*
* @param key 键 不能为null
* @param item 项 不能为null
* @return true 存在 false不存在
*/
public boolean hHasKey(String key, String item) {
return redisTemplate.opsForHash().hasKey(key, item);
}
/**
* hash递增 如果不存在,就会创建一个 并把新增后的值返回
*
* @param key 键
* @param item 项
* @param by 要增加几(大于0)
*/
public double hincr(String key, String item, double by) {
return redisTemplate.opsForHash().increment(key, item, by);
}
/**
* hash递减
*
* @param key 键
* @param item 项
* @param by 要减少记(小于0)
*/
public double hdecr(String key, String item, double by) {
return redisTemplate.opsForHash().increment(key, item, -by);
}
// ============================set=============================
/**
* 根据key获取Set中的所有值
* @param key 键
*/
public Set<Object> sGet(String key) {
try {
return redisTemplate.opsForSet().members(key);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* 根据value从一个set中查询,是否存在
*
* @param key 键
* @param value 值
* @return true 存在 false不存在
*/
public boolean sHasKey(String key, Object value) {
try {
return redisTemplate.opsForSet().isMember(key, value);
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 将数据放入set缓存
*
* @param key 键
* @param values 值 可以是多个
* @return 成功个数
*/
public long sSet(String key, Object... values) {
try {
return redisTemplate.opsForSet().add(key, values);
} catch (Exception e) {
e.printStackTrace();
return 0;
}
}
/**
* 将set数据放入缓存
*
* @param key 键
* @param time 时间(秒)
* @param values 值 可以是多个
* @return 成功个数
*/
public long sSetAndTime(String key, long time, Object... values) {
try {
Long count = redisTemplate.opsForSet().add(key, values);
if (time > 0)
expire(key, time);
return count;
} catch (Exception e) {
e.printStackTrace();
return 0;
}
}
/**
* 获取set缓存的长度
*
* @param key 键
*/
public long sGetSetSize(String key) {
try {
return redisTemplate.opsForSet().size(key);
} catch (Exception e) {
e.printStackTrace();
return 0;
}
}
/**
* 移除值为value的
*
* @param key 键
* @param values 值 可以是多个
* @return 移除的个数
*/
public long setRemove(String key, Object... values) {
try {
Long count = redisTemplate.opsForSet().remove(key, values);
return count;
} catch (Exception e) {
e.printStackTrace();
return 0;
}
}
// ===============================list=================================
/**
* 获取list缓存的内容
*
* @param key 键
* @param start 开始
* @param end 结束 0 到 -1代表所有值
*/
public List<Object> lGet(String key, long start, long end) {
try {
return redisTemplate.opsForList().range(key, start, end);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* 获取list缓存的长度
*
* @param key 键
*/
public long lGetListSize(String key) {
try {
return redisTemplate.opsForList().size(key);
} catch (Exception e) {
e.printStackTrace();
return 0;
}
}
/**
* 通过索引 获取list中的值
*
* @param key 键
* @param index 索引 index>=0时, 0 表头,1 第二个元素,依次类推;index<0时,-1,表尾,-2倒数第二个元素,依次类推
*/
public Object lGetIndex(String key, long index) {
try {
return redisTemplate.opsForList().index(key, index);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* 将list放入缓存
*
* @param key 键
* @param value 值
*/
public boolean lSet(String key, Object value) {
try {
redisTemplate.opsForList().rightPush(key, value);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 将list放入缓存
* @param key 键
* @param value 值
* @param time 时间(秒)
*/
public boolean lSet(String key, Object value, long time) {
try {
redisTemplate.opsForList().rightPush(key, value);
if (time > 0)
expire(key, time);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 将list放入缓存
*
* @param key 键
* @param value 值
* @return
*/
public boolean lSet(String key, List<Object> value) {
try {
redisTemplate.opsForList().rightPushAll(key, value);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 将list放入缓存
*
* @param key 键
* @param value 值
* @param time 时间(秒)
* @return
*/
public boolean lSet(String key, List<Object> value, long time) {
try {
redisTemplate.opsForList().rightPushAll(key, value);
if (time > 0)
expire(key, time);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 根据索引修改list中的某条数据
*
* @param key 键
* @param index 索引
* @param value 值
* @return
*/
public boolean lUpdateIndex(String key, long index, Object value) {
try {
redisTemplate.opsForList().set(key, index, value);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 移除N个值为value
*
* @param key 键
* @param count 移除多少个
* @param value 值
* @return 移除的个数
*/
public long lRemove(String key, long count, Object value) {
try {
Long remove = redisTemplate.opsForList().remove(key, count, value);
return remove;
} catch (Exception e) {
e.printStackTrace();
return 0;
}
}
}
在SpringbootRedisApplicationTests中使用RedisUtils工具类:
@Autowired
private RedisUtil redisUtil;
@Test
public void testRedisUtil() {
redisUtil.set("username","hello");
System.out.println(redisUtil.get("username"));
}