SSM整合shiro

article/2025/10/28 2:04:27

1.完成ssm整合shiro

企业中老项目还在使用ssm框架。

 准备数据库

 数据结构

张三 -user:query user:add user:update user:delete

李四 ---》user:query user:add user:update

王五-----》user:query user:export

搭建ssm的环境

(1)创建一个maven的web工程。

(2)ssm整合到web工程

1.pom依赖

<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>org.example</groupId><artifactId>ssm-shiro1029</artifactId><version>1.0-SNAPSHOT</version>
<!--版本和依赖分离--><properties><spring.version>5.2.15.RELEASE</spring.version></properties><dependencies><dependency><groupId>org.apache.shiro</groupId><artifactId>shiro-spring</artifactId><version>1.9.0</version></dependency><!--spring-webmvc--><dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId><version>${spring.version}</version></dependency><!--mybatis依赖--><dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>3.5.6</version></dependency><!--mybatis和spring整合的依赖--><dependency><groupId>org.mybatis</groupId><artifactId>mybatis-spring</artifactId><version>2.0.6</version></dependency><!--mysql驱动--><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.28</version></dependency><!--druid连接池依赖--><dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.2.1</version></dependency><!--lombok依赖--><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.24</version></dependency><!--jackson java对象转换为json对象 @ResponseBody--><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId><version>2.13.2.2</version></dependency><!--servlet-api依赖--><dependency><groupId>javax.servlet</groupId><artifactId>javax.servlet-api</artifactId><version>4.0.1</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-jdbc</artifactId><version>5.2.15.RELEASE</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-tx</artifactId><version>5.2.15.RELEASE</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-aspects</artifactId><version>5.2.15.RELEASE</version></dependency><!--generator--><dependency><groupId>org.mybatis.generator</groupId><artifactId>mybatis-generator-core</artifactId><version>1.4.0</version></dependency><dependency><groupId>com.github.pagehelper</groupId><artifactId>pagehelper</artifactId><version>5.3.0</version></dependency><dependency><groupId>log4j</groupId><artifactId>log4j</artifactId><version>1.2.17</version></dependency></dependencies></project>

2.spring配置文件(spring和springmvc配置在一起)

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context"xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"xmlns:mvc="http://www.springframework.org/schema/mvc"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd"><!-- 包扫描 --><context:component-scan base-package="com.wzh"/><!-- 开启注解 --><mvc:annotation-driven /><!-- 静态资源放行 --><mvc:default-servlet-handler/><!--视图解析器--><bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"><property name="prefix" value="WEB-INF/views/"/><property name="suffix" value=".jsp"/></bean><!-- 启动Shrio的注解 --><bean id="lifecycleBeanPostProcessor"class="org.apache.shiro.spring.LifecycleBeanPostProcessor" /><bean  class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"depends-on="lifecycleBeanPostProcessor" /><bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor"><property name="securityManager" ref="securityManager" /></bean><!-- 德鲁伊连接池 --><bean id="dataResource" class="com.alibaba.druid.pool.DruidDataSource"><!--驱动名称--><property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/><property name="url" value="jdbc:mysql://localhost:3306/shiro?serverTimezone=Asia/Shanghai"/><property name="username" value="root"/><property name="password" value="123456"/><!--初始化连接池的个数--><property name="initialSize" value="10"/><!--至少的个数--><property name="minIdle" value="5"/><!--最多的个数--><property name="maxActive" value="10"/><!--最长等待时间单位毫秒--><property name="maxWait" value="2000"/></bean><!--创建事务管理类--><bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"><property name="dataSource" ref="dataResource"/></bean><!--开启事务注解--><tx:annotation-driven transaction-manager="transactionManager"/><!-- sqlSessionFactoryBean --><bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"><property name="dataSource" ref="dataResource"/><!-- 配置映射文件 --><property name="mapperLocations" value="classpath:mapper/*.xml"/><!-- 配置分页 --><property name="plugins" ><array><bean class="com.github.pagehelper.PageInterceptor"/></array></property></bean><!--dao接口的代理实现类--><bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"><property name="basePackage" value="com.wzh.mapper"/></bean><!--下面是shiro中需要加的--><!--整合shiro的配置内容--><!--1、配置securityManager--><bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager"><property name="realm" ref="realm"/></bean><!--2、配置自定义的Realm--><bean id="realm" class="com.wzh.realm.MyRealm"><property name="credentialsMatcher" ref="credentialsMatcher"/></bean><!--3、创建密码匹配器--><bean id="credentialsMatcher" class="org.apache.shiro.authc.credential.HashedCredentialsMatcher"><property name="hashAlgorithmName" value="MD5"/><property name="hashIterations" value="1024"/></bean><!--shiro过滤工厂: 设置过滤的规则--><bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean"><!-- Shiro的核心安全接口,这个属性是必须的 --><property name="securityManager" ref="securityManager"/><!--设置未登录的跳转路径-->
<!--        <property name="loginUrl" value="/login.jsp"/>--><!--设置没有权限的跳转路径-->
<!--        <property name="unauthorizedUrl" value="/unauthorizedUrl.jsp"/>--><!--设置过滤器--><property name="filterChainDefinitions"><value>/login=anon/**=authc</value></property><!--未登录 过滤器--><property name="filters"><map><entry key="authc"><!--自定义过滤器所在的路径--><bean class="com.wzh.filter.LoginFilter"/></entry></map></property></bean></beans>

3.web.xml配置文件

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"version="4.0"><!--shiro过滤器的代理--><filter><filter-name>shiroFilter</filter-name><filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class></filter><filter-mapping><filter-name>shiroFilter</filter-name><url-pattern>/*</url-pattern></filter-mapping><!-- 注册servlet --><servlet><servlet-name>DispatcherServlet</servlet-name><servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class><init-param><param-name>contextConfigLocation</param-name><param-value>classpath:springmvc.xml</param-value></init-param><load-on-startup>1</load-on-startup></servlet><servlet-mapping><servlet-name>DispatcherServlet</servlet-name><url-pattern>/</url-pattern></servlet-mapping><!-- 解决中文乱码 注册文字格式拦截器 --><filter><filter-name>encodingFilter</filter-name><filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class><init-param><param-name>encoding</param-name><param-value>utf-8</param-value></init-param></filter><filter-mapping><filter-name>encodingFilter</filter-name><url-pattern>/*</url-pattern></filter-mapping></web-app>

上面是spring和springmvc配置文件在一起的,有的时候spring配置文件和springmvc文件没有在一起,如下

application.xml---spring配置文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context"xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"xmlns:mvc="http://www.springframework.org/schema/mvc"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd"><!-- 包扫描 --><context:component-scan base-package="com.wzh.service"/><!--导入db.properties--><!--引入属性文件--><context:property-placeholder location="classpath:db.properties"/><!--配置数据源--><bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"><property name="driverClassName" value="${jdbc.driver}"/><property name="url" value="${jdbc.url}"/><property name="username" value="${jdbc.username}"/><property name="password" value="${jdbc.password}"/></bean><!--SqlSessionFactoryBean--><bean id="sessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"><property name="dataSource" ref="dataSource"/><property name="mapperLocations" value="classpath:mapper/*.xml"/></bean><!--为Dao生成实现类--><bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"><property name="basePackage" value="com.wzh.dao"/></bean><!--事务--><bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"><property name="dataSource" ref="dataSource"/></bean><!--开启事务注解--><tx:annotation-driven transaction-manager="transactionManager"/>
</beans>

springmvc.xml配置文件:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context"xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"xmlns:mvc="http://www.springframework.org/schema/mvc"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd"><!-- 包扫描 --><context:component-scan base-package="com.wzh.controller"/><!--静态资源放行--><mvc:default-servlet-handler/><!--注解驱动--><mvc:annotation-driven/><!--视图解析器--><bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"><property name="prefix" value="WEB-INF/views/"/><property name="suffix" value=".jsp"/></bean>
</beans>

web.xml:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"version="4.0"><!--监听器   加载spring配置文件--><context-param><param-name>contextConfigLocation</param-name><param-value>classpath:application.xml</param-value></context-param><listener><listener-class>org.springframework.web.context.ContextLoaderListener</listener-class></listener><!-- 前端控制器 加载springmvc配置文件--><servlet><servlet-name>DispatcherServlet</servlet-name><servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class><init-param><param-name>contextConfigLocation</param-name><param-value>classpath:springmvc.xml</param-value></init-param><load-on-startup>1</load-on-startup></servlet><servlet-mapping><servlet-name>DispatcherServlet</servlet-name><url-pattern>/</url-pattern></servlet-mapping><!-- 解决中文乱码 注册文字格式拦截器 --><filter><filter-name>encodingFilter</filter-name><filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class><init-param><param-name>encoding</param-name><param-value>utf-8</param-value></init-param></filter><filter-mapping><filter-name>encodingFilter</filter-name><url-pattern>/*</url-pattern></filter-mapping></web-app>

4.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.wzh.mapper.PermissionMapper"></mapper>

controller  service dao entity文件夹创建  省略,

5.登录页面和成功页面准备好

 

 

整合shiro

        (1)引入shiro的依赖

 <!--shiro--><dependency><groupId>org.apache.shiro</groupId><artifactId>shiro-spring</artifactId><version>1.9.0</version></dependency>

        (2)spring的配置文件添加shiro的配置

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context"xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"xmlns:mvc="http://www.springframework.org/schema/mvc"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd"><!-- 包扫描 --><context:component-scan base-package="com.wzh.service"/><!--导入db.properties--><!--引入属性文件--><context:property-placeholder location="classpath:db.properties"/><!--配置数据源--><bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"><property name="driverClassName" value="${jdbc.driver}"/><property name="url" value="${jdbc.url}"/><property name="username" value="${jdbc.username}"/><property name="password" value="${jdbc.password}"/></bean><!--SqlSessionFactoryBean--><bean id="sessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"><property name="dataSource" ref="dataSource"/><property name="mapperLocations" value="classpath:mapper/*.xml"/></bean><!--为Dao生成实现类--><bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"><property name="basePackage" value="com.wzh.dao"/></bean><!--事务--><bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"><property name="dataSource" ref="dataSource"/></bean><!--开启事务注解--><tx:annotation-driven transaction-manager="transactionManager"/><!--spring整合shiro--><!--SecurityManager的管理--><bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager"><property name="realm" ref="myRealm"/></bean><!--创建Realm对象--><bean id="myRealm" class="com.wzh.realm.MyRealm"><property name="credentialsMatcher" ref="credentialsMatcher"/></bean><!--创建密码加密器--><bean id="credentialsMatcher" class="org.apache.shiro.authc.credential.HashedCredentialsMatcher"><property name="hashAlgorithmName" value="MD5"/><property name="hashIterations" value="1024"/></bean><!--设置shiro的过滤器链id:后面要求必须和web.xml中的配置名称相同--><bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean"><!--设置安全管理对象--><property name="securityManager" ref="securityManager"/><!--如果没有认证 则跳转到登录页面--><property name="loginUrl" value="/toLogin"/><!--如果没有权限,跳转的路径--><property name="unauthorizedUrl" value="/unauthorizedUrl.jsp"/><!--过滤器链--><!--anon:表示允许匿名访问authc:需要认证后才可以访问--><property name="filterChainDefinitions"><value>/index.jsp=anon/login=anon/**=authc</value></property></bean></beans>

如果jsp文件都在webapp下,并没有在WEB-INF下的views中设置如下:

 

 <!--整合shiro的配置内容--><!--①SecurityManager--><bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager"><property name="realm" ref="realm"/></bean><!--创建自定义realm类对象--><bean id="realm" class="com.ykq.realm.MyRealm"><property name="credentialsMatcher" ref="credentialsMatcher"/></bean><!--创建密码匹配器--><bean id="credentialsMatcher" class="org.apache.shiro.authc.credential.HashedCredentialsMatcher"><property name="hashAlgorithmName" value="MD5"/><property name="hashIterations" value="1024"/></bean><!--shiro过滤工厂: 设置过滤的规则--><bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean"><!--如果没有登录,跳转的路径--><property name="loginUrl" value="/login.jsp"/><!--没有权限,跳转的路径--><property name="unauthorizedUrl" value="/unauthorized.jsp"/><property name="filterChainDefinitions"><value>/login=anon/**=authc</value></property></bean>

 shiro中内置很多过滤器,而每个过滤都有相应的别名.

         (3) 修改web.xml文件

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"version="4.0"><!--shiro过滤器--><filter><!--该名称必须和ShiroFilterFactoryBean的id相同(也就是spring配置文件中的ShiroFilterFactoryBean)--><filter-name>shiroFilter</filter-name><filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class></filter><filter-mapping><filter-name>shiroFilter</filter-name><url-pattern>/*</url-pattern></filter-mapping><!--监听器   加载spring配置文件--><context-param><param-name>contextConfigLocation</param-name><param-value>classpath:application.xml</param-value></context-param><listener><listener-class>org.springframework.web.context.ContextLoaderListener</listener-class></listener><!-- 前端控制器 加载springmvc配置文件--><servlet><servlet-name>DispatcherServlet</servlet-name><servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class><init-param><param-name>contextConfigLocation</param-name><param-value>classpath:springmvc.xml</param-value></init-param><load-on-startup>1</load-on-startup></servlet><servlet-mapping><servlet-name>DispatcherServlet</servlet-name><url-pattern>/</url-pattern></servlet-mapping><!-- 解决中文乱码 注册文字格式拦截器 --><filter><filter-name>encodingFilter</filter-name><filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class><init-param><param-name>encoding</param-name><param-value>utf-8</param-value></init-param></filter><filter-mapping><filter-name>encodingFilter</filter-name><url-pattern>/*</url-pattern></filter-mapping></web-app>

 (4)controller

package com.wzh.controller;import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;/*** @ProjectName: ssm-shiro-1029* @Package: com.wzh.controller* @ClassName: PageController* @Author: 王振华* @Description:* @Date: 2022/10/29 19:07* @Version: 1.0*/
@Controller
public class PageController {@GetMapping("/toLogin")public String toLogin(){return "login";//经过视图解析器,找到WEB-INF/views下}@ResponseBody@RequestMapping("login")public String login(String username, String password) {System.out.println(username);//获取subject主体对象Subject subject = SecurityUtils.getSubject();UsernamePasswordToken token = new UsernamePasswordToken(username, password);try {subject.login(token);return "success";} catch (Exception e) {e.printStackTrace();return "fail";}}
}

(5) myRealm

package com.wzh.realm;import com.wzh.pojo.entity.User;
import com.wzh.service.UserService;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
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.util.ByteSource;import java.util.List;/*** @ProjectName: maven-shiro1028* @Package: com.wzh.realm* @ClassName: MyRealm* @Author: 王振华* @Description:* @Date: 2022/10/28 19:07* @Version: 1.0*/
public class MyRealm extends AuthorizingRealm {private UserService userService = new UserService();//授权时执行该方法@Overrideprotected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {return null;}//认证时执行该方法@Overrideprotected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {System.out.println("认证方法=====");//1.获取登录者的账号String username = authenticationToken.getPrincipal().toString();//2.根据账号查询数据库User user = userService.findByUsername(username);if(user!=null){//Object principal,账号数据库中// Object credentials,密码数据库中//ByteSource credentialsSalt 使用的盐// String realmName realm的名称随便起//密码的比对交于SimpleAuthenticationInfo//未来在数据中一列设置为存放盐ByteSource salt = ByteSource.Util.bytes(user.getSalt());SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user,user.getUserpwd(),salt,this.getName());return info;}return null;}
}

(6)service

package com.wzh.service;import com.wzh.dao.UserMapper;import com.wzh.pojo.entity.User;
import com.wzh.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;import java.util.List;/*** @ProjectName: ssm-shiro* @Package: com.wzh.service.impl* @ClassName: UserServiceImpl* @Author: 王振华* @Description:* @Date: 2022/8/4 22:20* @Version: 1.0*/
@Service
public class UserService {@Autowiredprivate UserMapper userMapper;public User findByUsername(String username) {if(username!=null&&username!="") {User user = userMapper.selectByUsername(username);return user;}return null;}}

 (7)userMapper.xml,dao层省略

<?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.wzh.dao.UserMapper"><select id="selectByUsername" resultType="com.wzh.pojo.entity.User">select * from user where username = #{username}</select>
</mapper>

1.1. 进入主页后,不同的用户可以看到不同的内容。

<%--Created by IntelliJ IDEA.User: m1762Date: 2022/8/4Time: 22:58To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="shiro" uri="http://shiro.apache.org/tags" %>
<html>
<head><title>Title</title>
</head>
<body><shiro:hasPermission name="user:query"><a href="/query">查询用户</a></shiro:hasPermission><shiro:hasPermission name="user:add"><a href="/add">添加用户</a></shiro:hasPermission><shiro:hasPermission name="user:delete"><a href="/delete">删除用户</a></shiro:hasPermission><shiro:hasPermission name="user:update"><a href="/update">修改用户</a></shiro:hasPermission><shiro:hasPermission name="user:export"><a href="/export">导出用户</a></shiro:hasPermission>
</body>
</html>

 可以在jsp中获取当前登录者的账号

<h1>欢迎<shiro:principal property="username"/>来到主页</h1>

 上面只是在网页中根据不同用户显示不同的菜单,这种方式只能防君子不能防小人。因为现在依旧可以通过postman访问没有的权限方法  比如张三可以访问到user:export路径

解决办法:

  1. 拦截器---获取请求路径 然后根据你的路径判断当前用户是否具有该权限。

  2. spring整合shiro时提供了一个注解:可以加载相应方法上。

使用注解:

1.springmvc.xml中启动shiro的注解

 <!-- 启动Shrio的注解 --><bean id="lifecycleBeanPostProcessor"class="org.apache.shiro.spring.LifecycleBeanPostProcessor" /><bean  class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"depends-on="lifecycleBeanPostProcessor" /><bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor"><property name="securityManager" ref="securityManager" /></bean>

(2)使用注解

 

这个太丑了,我们想要跳转一个页面,

我们之前学过全局异常处理:    没有登录会报这个异常

 

2.ssm整合shiro完成前后端分离

所谓前后端完全分离:后端响应的都是json数据,而不再是网页。  

我们需要修改的就是:

1. 登录成功或者失败应该返回json数据
2. 当未登录时返回的也是json数据
3. 访问未授权的资源,也要分会json。

2.1.登录成功或者失败应该返回json数据

修改登录接口

2.2 当未登录时返回的也是json数据

(1)创建一个过滤器,继承登录校验的FormAuthenticationFilter接口。

package com.wzh.filter;import com.fasterxml.jackson.databind.ObjectMapper;
import com.wzh.utils.CommonResult;
import org.apache.shiro.web.filter.authc.FormAuthenticationFilter;import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import java.io.PrintWriter;/*** @ProjectName: shiro-ssm0805* @Package: com.wzh.filter* @ClassName: LoginFilter* @Author: 王振华* @Description:* @Date: 2022/8/5 16:58* @Version: 1.0*/
public class LoginFilter extends FormAuthenticationFilter {/*** 当没有登录时会经过该方法,如果想让它返回json数据必须重写onAccessDenied这个方法* @param request* @param response* @return* @throws Exception*/@Overrideprotected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {response.setContentType("application/json;charset=utf-8");PrintWriter writer = response.getWriter();CommonResult commonResult = CommonResult.UNLOGIN;//jackson中内置对象   将java对象转为json对象ObjectMapper objectMapper = new ObjectMapper();String json = objectMapper.writeValueAsString(commonResult);//响应给客户json数据writer.print(json);writer.flush();writer.close();return false;}
}

之前默认是在springmvc.xml中配置的跳转页面

(2) 注册我们的过滤器

 2.3 如果没有权限应该返回json数据

3.项目完整代码

项目结构:

Controller层:

 UserController:    用于登录    调用login方法判断是否身份认证  授权

package com.wzh.controller;import com.wzh.utils.CommonResult;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;/*** @ProjectName: ssm-shiro* @Package: com.wzh.controller* @ClassName: UserController* @Author: 王振华* @Description:* @Date: 2022/8/4 22:07* @Version: 1.0*/
@RestController
public class UserController {@RequestMapping("login")public CommonResult login(String username,String password){System.out.println(username);//获取subject主体对象Subject subject = SecurityUtils.getSubject();UsernamePasswordToken token = new UsernamePasswordToken(username, password);try{subject.login(token);System.out.println("是否身份认证:"+subject.isAuthenticated());System.out.println("是否授权:"+subject.isPermitted("查询"));System.out.println("是否授权:"+subject.isPermitted("添加"));System.out.println("是否授权:"+subject.isPermitted("修改"));System.out.println("是否授权:"+subject.isPermitted("删除"));System.out.println("是否授权:"+subject.isPermitted("导出"));System.out.println("是否授权:"+subject.hasRole("超级管理员"));System.out.println("是否授权:"+subject.hasRole("管理员"));System.out.println("是否授权:"+subject.hasRole("用户"));return CommonResult.LOGIN_SUCCESS;}catch (Exception e){e.printStackTrace();return CommonResult.LOGIN_ERROR;}}
}

PermissionController:      用于登录之后查看是否授权

package com.wzh.controller;import com.wzh.utils.CommonResult;
import org.apache.shiro.authz.annotation.Logical;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;/*** @ProjectName: shiro-ssm0805* @Package: com.wzh.controller* @ClassName: PermissionController* @Author: 王振华* @Description:* @Date: 2022/8/5 9:57* @Version: 1.0*/
@RestController
public class PermissionController {@GetMapping("/query")//使用shiro注解@RequiresPermissions(value = {"user:query","user:aaa"},logical = Logical.OR)public String query(){return "query";}@RequestMapping("/add")@RequiresPermissions(value = {"user:add"})public String add(){return "add";}@RequestMapping("/delete")@RequiresPermissions(value = {"user:delete"})public String delete(){return "delete";}@RequestMapping("/update")@RequiresPermissions(value = {"user:update"})public String update(){return "update";}@RequestMapping("/export")@RequiresPermissions(value = {"user:export"})public String export(){return "export";}
}

service层:

UserService:

package com.wzh.service;import com.wzh.entity.User;import java.util.List;/*** @ProjectName: ssm-shiro* @Package: com.wzh.service* @ClassName: UserService* @Author: 王振华* @Description:* @Date: 2022/8/4 22:19* @Version: 1.0*/
public interface UserService {User findByUsername(String username);}

PermissionService:

package com.wzh.service;import java.util.List;/*** @ProjectName: ssm-shiro* @Package: com.wzh.service* @ClassName: PermissionService* @Author: 王振华* @Description:* @Date: 2022/8/4 22:27* @Version: 1.0*/
public interface PermissionService {List<String> findPermissionById(Integer userid);
}

RoleService:

package com.wzh.service;import java.util.List;/*** @ProjectName: ssm-shiro* @Package: com.wzh.service* @ClassName: RoleService* @Author: 王振华* @Description:* @Date: 2022/8/4 22:27* @Version: 1.0*/
public interface RoleService {List<String> findRolesById(Integer userid);
}

UserServiceImpl:

package com.wzh.service.impl;import com.wzh.entity.User;
import com.wzh.mapper.UserMapper;
import com.wzh.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;import java.util.List;/*** @ProjectName: ssm-shiro* @Package: com.wzh.service.impl* @ClassName: UserServiceImpl* @Author: 王振华* @Description:* @Date: 2022/8/4 22:20* @Version: 1.0*/
@Service
public class UserServiceImpl implements UserService {@Autowiredprivate UserMapper userMapper;@Overridepublic User findByUsername(String username) {if(username!=null&&username!="") {User user = userMapper.selectByUsername(username);return user;}return null;}}

PermissionServiceImpl:

package com.wzh.service.impl;import com.wzh.mapper.PermissionMapper;
import com.wzh.service.PermissionService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;import java.util.ArrayList;
import java.util.List;/*** @ProjectName: ssm-shiro* @Package: com.wzh.service.impl* @ClassName: PermissionServiceImpl* @Author: 王振华* @Description:* @Date: 2022/8/4 22:28* @Version: 1.0*/
@Service
public class PermissionServiceImpl implements PermissionService {@Autowiredprivate PermissionMapper permissionMapper;@Overridepublic List<String> findPermissionById(Integer userid) {List<String> list = permissionMapper.selectByUserId(userid);return list;}
}

RoleServiceImpl:

package com.wzh.service.impl;import com.wzh.mapper.RoleMapper;
import com.wzh.service.RoleService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;import java.util.List;/*** @ProjectName: ssm-shiro* @Package: com.wzh.service.impl* @ClassName: RoleServiceImpl* @Author: 王振华* @Description:* @Date: 2022/8/4 22:28* @Version: 1.0*/
@Service
public class RoleServiceImpl implements RoleService {@Autowiredprivate RoleMapper roleMapper;@Overridepublic List<String> findRolesById(Integer userid) {List<String> list = roleMapper.selectByUserId(userid);return list;}
}

mapper层:

UserMapper:

package com.wzh.mapper;import com.wzh.entity.User;import java.util.List;/*** @ProjectName: ssm-shiro* @Package: com.wzh.mapper* @ClassName: UserMapper* @Author: 王振华* @Description:* @Date: 2022/8/4 22:21* @Version: 1.0*/
public interface UserMapper {User selectByUsername(String username);}

PermissionMapper:

package com.wzh.mapper;import java.util.List;/**@ProjectName: ssm-shiro
@Package: com.wzh.mapper
@ClassName: PermissionMapper
@Author: 王振华
@Description: 
@Date: 2022/8/4 22:21
@Version: 1.0
*/
public interface PermissionMapper {List<String> selectByUserId(Integer userid);
}

RoleMapper:

package com.wzh.mapper;import java.util.List;/*** @ProjectName: ssm-shiro* @Package: com.wzh.mapper* @ClassName: RoleMapper* @Author: 王振华* @Description:* @Date: 2022/8/4 22:21* @Version: 1.0*/public interface RoleMapper {List<String> selectByUserId(Integer userid);
}

entity层:

User:

package com.wzh.entity;import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;import javax.management.relation.Role;/*** @ProjectName: ssm-shiro* @Package: com.wzh.entity* @ClassName: User* @Author: 王振华* @Description:* @Date: 2022/8/4 22:19* @Version: 1.0*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {private Integer userid;private String username;private String userpwd;private String sex;private String address;private String salt;private Permission permission;private Role role;
}

Permission:

package com.wzh.entity;import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;/*** @ProjectName: ssm-shiro* @Package: com.wzh.entity* @ClassName: Permission* @Author: 王振华* @Description:* @Date: 2022/8/4 22:22* @Version: 1.0*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Permission {private Integer perid;private String pername;private String percode;
}

Role:

package com.wzh.entity;import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;/*** @ProjectName: ssm-shiro* @Package: com.wzh.entity* @ClassName: Role* @Author: 王振华* @Description:* @Date: 2022/8/4 22:22* @Version: 1.0*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Role {private Integer roleid;private String rolename;
}

filter:

LoginFilter:   用于未登录返回json数据

package com.wzh.filter;import com.fasterxml.jackson.databind.ObjectMapper;
import com.wzh.utils.CommonResult;
import org.apache.shiro.web.filter.authc.FormAuthenticationFilter;import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import java.io.PrintWriter;/*** @ProjectName: shiro-ssm0805* @Package: com.wzh.filter* @ClassName: LoginFilter* @Author: 王振华* @Description:* @Date: 2022/8/5 16:58* @Version: 1.0*/
public class LoginFilter extends FormAuthenticationFilter {/*** 当没有登录时会经过该方法,如果想让它返回json数据必须重写onAccessDenied这个方法* @param request* @param response* @return* @throws Exception*/@Overrideprotected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {response.setContentType("application/json;charset=utf-8");PrintWriter writer = response.getWriter();CommonResult commonResult = CommonResult.UNLOGIN;//jackson中内置对象   将java对象转为json对象ObjectMapper objectMapper = new ObjectMapper();String json = objectMapper.writeValueAsString(commonResult);//响应给客户json数据writer.print(json);writer.flush();writer.close();return false;}
}

handler:  全局异常处理类   用户没有权限返回json数据给前端

MyException:

package com.wzh.handler;import com.wzh.utils.CommonResult;
import org.apache.shiro.authz.UnauthorizedException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;/*** @ProjectName: shiro-ssm0805* @Package: com.wzh.handler* @ClassName: MyException* @Author: 王振华* @Description:* @Date: 2022/8/5 16:42* @Version: 1.0*/
@ControllerAdvice   //异常处理类
public class MyException {//当发生该异常时触发该方法@ExceptionHandler(value = UnauthorizedException.class)@ResponseBodypublic CommonResult Unauth(UnauthorizedException e){e.printStackTrace();return CommonResult.UNAUTHORIZED;}
}

realm:   自定义的认证授权规则

MyRealm:

package com.wzh.realm;import com.wzh.entity.User;
import com.wzh.service.PermissionService;
import com.wzh.service.RoleService;
import com.wzh.service.UserService;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
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.util.ByteSource;
import org.springframework.beans.factory.annotation.Autowired;import java.util.List;/*** @ProjectName: shiro* @Package: com.wzh.demo02* @ClassName: MyRealm* @Author: 王振华* @Description:* @Date: 2022/8/4 19:44* @Version: 1.0*/
public class MyRealm extends AuthorizingRealm {@Autowiredprivate UserService userService;@Autowiredprivate PermissionService permissionService;@Autowiredprivate RoleService roleService;@Override//该方法用于完成认证的功能protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {//1.根据token获取账号String username = (String) authenticationToken.getPrincipal();/*** 以前登陆的逻辑是  把用户和密码全部发到数据库  去匹配* 在shrio里面是先根据用户名把用户对象查询出来,再来做密码匹配*///2.根据账号查询用户信息User user = userService.findByUsername(username);//表示该用户名在数据库中存在if(user!=null){/*** 参数说明* 参数1:可以传到任意对象* 参数2:从数据库里面查询出来的密码* 参数3:盐* 参数4:当前类名*/ByteSource credentialsSalt = ByteSource.Util.bytes(user.getSalt());SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user, user.getUserpwd(),credentialsSalt,this.getName());return info;}//用户不存在  shiro会抛 UnknowAccountExceptionreturn null;}//授权@Overrideprotected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {User user = (User) principalCollection.getPrimaryPrincipal();SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();//根据账号查找该用户具有哪些权限List<String> list = permissionService.findPermissionById(user.getUserid());if(list!=null&&list.size()>0){info.addStringPermissions(list);}List<String> roles = roleService.findRolesById(user.getUserid());if(roles!=null&&roles.size()>0){info.addRoles(roles);}return info;}}

util:

CommonResult:

package com.wzh.utils;import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;/*** @ProjectName: shiro-ssm0805* @Package: com.wzh.utils* @ClassName: CommonResult* @Author: 王振华* @Description:* @Date: 2022/8/5 11:02* @Version: 1.0*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class CommonResult {public static final CommonResult UNLOGIN = new CommonResult(403,"未登录",null);public static final CommonResult UNAUTHORIZED = new CommonResult(405,"未授权",null);public static final CommonResult LOGIN_SUCCESS = new CommonResult(200,"登录成功",null);public static final CommonResult LOGIN_ERROR = new CommonResult(-1,"登录失败",null);private Integer code;private String msg;private Object data;}


http://chatgpt.dhexx.cn/article/jsEO4b0j.shtml

相关文章

SSM整合

1、ssm整合原理 SSM框架是spring MVC &#xff0c;spring和mybatis框架的整合&#xff0c;是标准的MVC模式&#xff0c;将整个系统划分为表现层&#xff0c;controller层&#xff0c;service层&#xff0c;DAO层四层。 使用spring MVC负责请求的转发和视图管理 spring实现业…

SSM整合,手把手教程,详解思路讲解

前言 一&#xff0c;工程创建 1.新建Maven项目&#xff0c;项目架构增加web支持 2.Maven本地仓库配置 3.集成Tomcat&#xff0c;搭建web环境 二&#xff0c;导入依赖 三&#xff0c;配置文件编写 1.web环境配置文件 2.spring整合环境配置文件 2.1 controller层(spring…

SSM整合完整流程讲解

目录 一、SSM整合说明 1、各个框架担任的角色 2、两个Ioc容器的创建顺序 1&#xff09;SpringMVC中IOC容器的创建时间 2&#xff09;Spring中IOC容器的创建时间 3&#xff09;Spring提供的监听器ContextLoaderListener 二、SSM整合步骤 1、准备工作 1&#xff09;导入…

Unresolved Dependencies

在Android Studio的开发中&#xff0c;在软件中集成了ButterKnife插件&#xff0c;另外需要集成ButterKnife的jar包。因为本地没有现成的&#xff0c;所以在module的build.gradle文件中添加了如下代码&#xff1a; compile com.jakewharton:butterknife:7.0.1 结果报了如下错误…

Pycharm 出现Unresolved reference ‘‘ 错误的解决方法 --- 亲测有效

在用Pycharm写项目的时候的时候碰到一个很无语的问题 路径明明没有问题&#xff0c;运行也没有出错&#xff0c;但就是爆红&#xff0c;逼死强迫症啊。。。 多方查找最后解决了。步骤如下&#xff1a; File–>Settings–>Project Structure–>找到问题目录–>Sou…

PyCharm错误提示- Unresolved reference 的解决

使用PyCharm加载工程时,发生解析错误 原本这个工程是可以通过 python manange.py runserver 方式运行的,说明文件是正常的。关键在于PyCharm环境的问题。 查找了半天,安装一些网上的解决方式,尝试了以下几种方式: 1,修改忽略文件 File –>Settings –>Editor –…

Goland 提示 Unresolved reference 错误解决

之前一直正常的项目&#xff0c;莫名其妙的 database/sql 包下的方法、结构体等等IDE都无法识别&#xff0c;出现一堆Unresolved reference错误提示&#xff0c;但包导入路径可以正确定位&#xff0c;而且项目运行也正常&#xff0c;其他包都正常&#xff0c;另一个项目下同样使…

error LNK2019: unresolved external symbol

error LNK2019: unresolved external symbol&#xff1a;链接器找不到所需要的东西 此时ctrlF7进行编译&#xff0c;没有报错&#xff0c;在这个程序中调用的是Log函数&#xff0c;我们实际上并没有这个函数&#xff0c; 我们有的函数是Logr函数&#xff0c;在编译过程中编译器…

Unresolved reference ‘matplotlib‘解决方法

首先打开最左边的file-settings 然后点这个添加 找想添加的 最后点最下面的install Package 就可以啦

快速解决Pycharm中unresolved reference

在用Pycharm时老是报红&#xff0c;虽然不影响运行&#xff0c;但是真的很不好看。 如下&#xff1a; 根据网上大部分教程设置source root&#xff0c;设置之后还是没有变化。 然后我发现了这个东西&#xff0c;真的是立即生效&#xff0c;就是不知道改了之后有没有什么后遗症…

解决unresolved symbol _RamfuncsLoadEnd

问题描述 移植大佬的文件之后&#xff0c;发现报错 问题解决 添加F28335.cmd到工程中

Redisson cannot use an unresolved DNS server address问题解决

概述 本文记录Mac IDEA开发&#xff0c;公司 远程办公时遇到的两个问题&#xff0c;记录一下。 问题 cannot use an unresolved DNS server address: [fe80::1%en0]:53 在家里&#xff0c;连上公司的VPN后&#xff0c;即可打开公司内网&#xff0c;远程办公。一切正常。某…

解决模块Unresolved Link问题

修改内容为下面的&#xff0c;请复制以下内容&#xff08;图中大小写有误&#xff09;&#xff01;&#xff01; Solver_SF/CarSim S-Function 此时就可以修改Simfile name了

c语言1 unresolved externals,出现了 unresolved external symbol _main和1 unresolved externals这是什么问题?...

满意答案 nyjspj 2014.01.18 采纳率&#xff1a;53% 等级&#xff1a;12 已帮助&#xff1a;5918人 {} 数量不匹配 #include #include "process.h" #include "stdio.h" #include "sqstack.h" template void convert(T n,T m) { T e; char c; …

AndroidStudio Unresolved reference

在学习Kotlin过程中&#xff0c;出现了两次在activity_main.xml中已注册id&#xff0c;但是在MainActivity.kt中无法找到该Button的情况。 后面发现是没有在build.gradle中导入 kotin-android-extensions’的包&#xff0c;导致无法 import kotlinx.android.synthetic.main.a…

Unresolved reference ‘SQLAlchemy‘

引用不到包的问题&#xff1b;setting已经添加了&#xff0c;外面是是报错 最后直接用pip下载包 pip install flask_sqlalchemy 就ok了

PyCharm报错Unresolved Reference

两台不同的电脑&#xff0c;开发相同的软件时&#xff0c;一台电脑总是报错Unresolved Reference&#xff0c;解决办法如下&#xff1a;

Goland Unresolved dependency问题解决

Goland Unresolved dependency 每次新建项目都会遇到这个提示&#xff0c;明明安装依赖包了&#xff0c; 能用&#xff0c;就是爆红。 解决办法是在 Goland 设置里将 Go Modules 开启即可。

Unresolved reference: BR

我遇到的问题是JDK版本过新导致的找不到资源 在Android studio Fox版本里默认是jdk11改为1.8即可成功编译

Unresolved reference: setOnclicklistener

问题描述&#xff1a;我在学习Android studio的时候&#xff0c;尝试用Button控件的setOnClickButtonListener函数。但是发现即使已经导入了andriod.widget.Button库&#xff0c;也不能自动导入此函数&#xff08;如下图&#xff09;&#xff1a; package com.example.homewor…