一、需求

  将原来基于url的工程改成使用shiro实现

二、代码

  https://github.com/bjlhx15/shiro.git 中的permission_shiro

三、去除原项目拦截器

  去掉springmvc.xml中配置的LoginInterceptor和PermissionInterceptor拦截器。<mvc:interceptors>

四、pom  

<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>com.lhx.shiro</groupId>
<artifactId>permission-shiro</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>war</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<spring.version>4.3.7.RELEASE</spring.version>
<shiro.version>1.3.2</shiro.version>
</properties>
<dependencies>
<!-- shiro 开始 -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
<version>${shiro.version}</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-web</artifactId>
<version>${shiro.version}</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>${shiro.version}</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-ehcache</artifactId>
<version>${shiro.version}</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-quartz</artifactId>
<version>${shiro.version}</version>
</dependency> <!-- shiro 结束 --> <dependency>
<groupId>commons-beanutils</groupId>
<artifactId>commons-beanutils</artifactId>
<version>1.8.3</version>
</dependency>
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>1.1.0.Final</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>5.2.4.Final</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.38</version>
</dependency>
<dependency>
<groupId>commons-dbcp</groupId>
<artifactId>commons-dbcp</artifactId>
<version>1.4</version>
</dependency>
<dependency>
<groupId>commons-pool</groupId>
<artifactId>commons-pool</artifactId>
<version>1.6</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.1</version>
</dependency> <dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.3.0</version>
</dependency>
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.1</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.4</version>
</dependency> <dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>taglibs</groupId>
<artifactId>standard</artifactId>
<version>1.1.2</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.21</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.21</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.7</source>
<target>1.7</target>
</configuration>
<version>3.3</version>
</plugin>
<plugin>
<!-- 命令:mvn mybatis-generator:generate -->
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-maven-plugin</artifactId>
<version>1.3.5</version>
<configuration>
<configurationFile>src/main/resources/generatorConfig.xml</configurationFile>
<verbose>true</verbose>
<overwrite>true</overwrite>
</configuration>
<dependencies>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.38</version>
</dependency>
<dependency>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-core</artifactId>
<version>1.3.5</version>
</dependency>
</dependencies>
</plugin>
</plugins>
</build>
</project>

五、web.xml中的shiro filter

  在web系统中,shiro也通过filter进行拦截。filter拦截后将操作权交给spring中配置的filterChain(过虑链儿)shiro提供很多filter。

  在web.xml中配置filter

    <!-- shiro过虑器,DelegatingFilterProxy通过代理模式将spring容器中的bean和filter关联起来 -->
<filter>
<filter-name>shiroFilter</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
<!-- 设置true由servlet容器控制filter的生命周期 -->
<init-param>
<param-name>targetFilterLifecycle</param-name>
<param-value>true</param-value>
</init-param>
<!-- 设置spring容器filter的bean id,如果不设置则找与filter-name一致的bean -->
<init-param>
<param-name>targetBeanName</param-name>
<param-value>shiroFilter</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>shiroFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

  securityManager:这个属性是必须的。

  loginUrl:没有登录认证的用户请求将跳转到此地址进行认证,不是必须的属性,不输入地址的话会自动寻找项目web项目的根目录下的”/login.jsp”页面。

  unauthorizedUrl:没有权限默认跳转的页面。

六、application-shiro.xml

在applicationContext-shiro.xml 中配置web.xml中fitler对应spring容器中的bean

<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.3.xsd"> <!-- web.xml中shiro的filter对应的bean -->
<!-- Shiro 的Web过滤器 -->
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<property name="securityManager" ref="securityManager"/>
<!-- loginUrl认证提交地址,如果没有认证将会请求此地址进行认证,请求此地址将由formAuthenticationFilter进行表单认证 -->
<property name="loginUrl" value="/login.action"/>
<!-- 认证成功统一跳转到first.action,建议不配置,shiro认证成功自动到上一个请求路径 -->
<property name="successUrl" value="/first.action"/>
<!-- 通过unauthorizedUrl指定没有权限操作时跳转页面 -->
<property name="unauthorizedUrl" value="/refuse.jsp"/>
<!-- 自定义filter配置 -->
<property name="filters">
<map>
<!-- 将自定义 的FormAuthenticationFilter注入shiroFilter中 -->
<entry key="authc" value-ref="formAuthenticationFilter"/>
</map>
</property> <!-- 过虑器链定义,从上向下顺序执行,一般将/**放在最下边 -->
<property name="filterChainDefinitions">
<value>
<!-- 对静态资源设置匿名访问 -->
/images/** = anon
/js/** = anon
/styles/** = anon
<!-- 验证码,可匿名访问 -->
/validatecode.jsp = anon <!-- 请求 logout.action地址,shiro去清除session -->
/logout.action = logout
<!--商品查询需要商品查询权限 ,取消url拦截配置,使用注解授权方式 -->
<!-- /items/queryItems.action = perms[item:query] /items/editItems.action
= perms[item:edit] -->
<!-- 配置记住我或认证通过可以访问的地址 -->
/index.jsp = user
/first.action = user
/welcome.jsp = user
<!-- /** = authc 所有url都必须认证通过才可以访问 -->
/** = authc
<!-- /** = anon所有url都可以匿名访问 --> </value>
</property>
</bean> <!-- securityManager安全管理器 -->
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<property name="realm" ref="customRealm"/>
<!-- 注入缓存管理器 -->
<property name="cacheManager" ref="cacheManager"/>
<!-- 注入session管理器 -->
<property name="sessionManager" ref="sessionManager"/>
<!-- 记住我 -->
<property name="rememberMeManager" ref="rememberMeManager"/> </bean> <!-- realm -->
<bean id="customRealm" class="com.lhx.ssm.shiro.CustomRealm">
<!-- 将凭证匹配器设置到realm中,realm按照凭证匹配器的要求进行散列 -->
<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="1"/>
</bean> <!-- 缓存管理器 -->
<bean id="cacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager">
<property name="cacheManagerConfigFile" value="classpath:shiro-ehcache.xml"/>
</bean> <!-- 会话管理器 -->
<bean id="sessionManager"
class="org.apache.shiro.web.session.mgt.DefaultWebSessionManager">
<!-- session的失效时长,单位毫秒 -->
<property name="globalSessionTimeout" value="600000"/>
<!-- 删除失效的session -->
<property name="deleteInvalidSessions" value="true"/>
</bean> <!-- 自定义form认证过虑器 -->
<!-- 基于Form表单的身份验证过滤器,不配置将也会注册此过虑器,表单中的用户账号、密码及loginurl将采用默认值,建议配置 -->
<bean id="formAuthenticationFilter" class="com.lhx.ssm.shiro.CustomFormAuthenticationFilter">
<!-- 表单中账号的input名称 -->
<property name="usernameParam" value="username"/>
<!-- 表单中密码的input名称 -->
<property name="passwordParam" value="password"/>
<!-- 记住我input的名称 -->
<property name="rememberMeParam" value="rememberMe"/>
</bean> <!-- rememberMeManager管理器,写cookie,取出cookie生成用户信息 -->
<bean id="rememberMeManager" class="org.apache.shiro.web.mgt.CookieRememberMeManager">
<property name="cookie" ref="rememberMeCookie"/>
</bean>
<!-- 记住我cookie -->
<bean id="rememberMeCookie" class="org.apache.shiro.web.servlet.SimpleCookie">
<!-- rememberMe是cookie的名字 -->
<constructor-arg value="rememberMe"/>
<!-- 记住我cookie生效时间30天 -->
<property name="maxAge" value="2592000"/>
</bean>
</beans>

七、自定义realm

此realm先不从数据库查询权限数据,当前需要先将shiro整合完成,在上边章节定义的realm基础上修改。

public class CustomRealm extends AuthorizingRealm {

    @Override
public String getName() {
return "customRealm";
} // 支持什么类型的token
@Override
public boolean supports(AuthenticationToken token) {
return token instanceof UsernamePasswordToken;
} // 认证
@Override
protected AuthenticationInfo doGetAuthenticationInfo(
AuthenticationToken token) throws AuthenticationException { // 从token中 获取用户身份信息
String username = (String) token.getPrincipal();
// 拿username从数据库中查询
// ....
// 如果查询不到则返回null
if (!username.equals("zhang")) {// 这里模拟查询不到
return null;
} // 获取从数据库查询出来的用户密码
String password = "123";// 这里使用静态数据模拟。。 // 根据用户id从数据库取出菜单
//...先用静态数据
List<SysPermission> menus = new ArrayList<SysPermission>();; SysPermission sysPermission_1 = new SysPermission();
sysPermission_1.setName("商品管理");
sysPermission_1.setUrl("/item/queryItem.action");
SysPermission sysPermission_2 = new SysPermission();
sysPermission_2.setName("用户管理");
sysPermission_2.setUrl("/user/query.action"); menus.add(sysPermission_1);
menus.add(sysPermission_2); // 构建用户身份信息
ActiveUser activeUser = new ActiveUser();
activeUser.setUserid(username);
activeUser.setUsername(username);
activeUser.setUsercode(username);
activeUser.setMenus(menus); // 返回认证信息由父类AuthenticatingRealm进行认证
SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(
activeUser, password, getName()); return simpleAuthenticationInfo;
} // 授权
@Override
protected AuthorizationInfo doGetAuthorizationInfo(
PrincipalCollection principals) {
// 获取身份信息
ActiveUser activeUser = (ActiveUser) principals.getPrimaryPrincipal();
//用户id
String userid = activeUser.getUserid();
// 根据用户id从数据库中查询权限数据
// ....这里使用静态数据模拟
List<String> permissions = new ArrayList<String>();
permissions.add("item:query");
permissions.add("item:update"); // 将权限信息封闭为AuthorizationInfo SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
for (String permission : permissions) {
simpleAuthorizationInfo.addStringPermission(permission);
} return simpleAuthorizationInfo;
} }

八、静态资源

对静态资源设置逆名访问:

修改applicationContext-shiro.xml:

                <!-- 对静态资源设置匿名访问 -->
/images/** = anon
/js/** = anon
/styles/** = anon

九、登录

9.1、原理

  使用FormAuthenticationFilter过虑器实现 ,原理如下:

    1、将用户没有认证时,请求loginurl进行认证,用户身份和用户密码提交数据到loginurl

    2、FormAuthenticationFilter拦截住取出request中的username和password(两个参数名称是可以配置的)

    3、FormAuthenticationFilter调用realm传入一个token(username和password)

    4、realm认证时根据username查询用户信息(在Activeuser中存储,包括 userid、usercode、username、menus)。

      如果查询不到,realm返回null,FormAuthenticationFilter向request域中填充一个参数(记录了异常信息)

9.2、登录页面

  由于FormAuthenticationFilter的用户身份和密码的input的默认值(username和password),修改页面的账号和密码 的input的名称为username和password

9.3、登录代码的实现  

    // 登陆提交地址,和applicationContext-shiro.xml中配置的loginurl一致
@RequestMapping("login")
public String login(HttpServletRequest request) throws Exception {
// 如果登陆失败从request中获取认证异常信息,shiroLoginFailure就是shiro异常类的全限定名
String exceptionClassName = (String) request.getAttribute("shiroLoginFailure");
// 根据shiro返回的异常类路径判断,抛出指定异常信息
if (exceptionClassName != null) {
if (UnknownAccountException.class.getName().equals(exceptionClassName)) {
// 最终会抛给异常处理器
throw new CustomException("账号不存在");
} else if (IncorrectCredentialsException.class.getName().equals(exceptionClassName)) {
throw new CustomException("用户名/密码错误");
} else if ("randomCodeError".equals(exceptionClassName)) {
throw new CustomException("验证码错误 ");
} else {
throw new Exception();// 最终在异常处理器生成未知错误
}
}
// 此方法不处理登陆成功(认证成功),shiro认证成功会自动跳转到上一个请求路径
// 登陆失败还到login页面
return "login";
}

9.4、认证拦截器过滤

在applicationContext-shiro.xml中配置:

                <!-- /** = authc 所有url都必须认证通过才可以访问 -->
/** = authc

十、退出

  由于使用shiro的sessionManager,不用开发退出功能,使用shiro的logout拦截器即可

  在applicationContext-shiro.xml配置LogoutFilter:

<!-- 退出拦截,请求logout.action执行退出操作 -->
/logout.action = logout

可以删除原来的logout的controller方法代码。

十一、无权限refuse.jsp

在applicationContext-shiro.xml配置LogoutFilter:

        <!-- 通过unauthorizedUrl指定没有权限操作时跳转页面 -->
<property name="unauthorizedUrl" value="/refuse.jsp"/>

十二、shiro过滤器总结

过滤器简称

对应的java类

anon

org.apache.shiro.web.filter.authc.AnonymousFilter

authc

org.apache.shiro.web.filter.authc.FormAuthenticationFilter

authcBasic

org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter

perms

org.apache.shiro.web.filter.authz.PermissionsAuthorizationFilter

port

org.apache.shiro.web.filter.authz.PortFilter

rest

org.apache.shiro.web.filter.authz.HttpMethodPermissionFilter

roles

org.apache.shiro.web.filter.authz.RolesAuthorizationFilter

ssl

org.apache.shiro.web.filter.authz.SslFilter

user

org.apache.shiro.web.filter.authc.UserFilter

logout

org.apache.shiro.web.filter.authc.LogoutFilter

anon:例子/admins/**=anon 没有参数,表示可以匿名使用。

authc:例如/admins/user/**=authc表示需要认证(登录)才能使用,FormAuthenticationFilter是表单认证,没有参数

roles:例子/admins/user/**=roles[admin],参数可以写多个,多个时必须加上引号,并且参数之间用逗号分割,当有多个参数时,例如admins/user/**=roles["admin,guest"],每个参数通过才算通过,相当于hasAllRoles()方法。

perms:例子/admins/user/**=perms[user:add:*],参数可以写多个,多个时必须加上引号,并且参数之间用逗号分割,例如/admins/user/**=perms["user:add:*,user:modify:*"],当有多个参数时必须每个参数都通过才通过,想当于isPermitedAll()方法。

rest:例子/admins/user/**=rest[user],根据请求的方法,相当于/admins/user/**=perms[user:method] ,其中method为post,get,delete等。

port:例子/admins/user/**=port[8081],当请求的url的端口不是8081是跳转到schemal://serverName:8081?queryString,其中schmal是协议http或https等,serverName是你访问的host,8081是url配置里port的端口,queryString是你访问的url里的?后面的参数。

authcBasic:例如/admins/user/**=authcBasic没有参数表示httpBasic认证

ssl:例子/admins/user/**=ssl没有参数,表示安全的url请求,协议为https

user:例如/admins/user/**=user没有参数表示必须存在用户, 身份认证通过或通过记住我认证通过的可以访问,当登入操作时不做检查

注:

anon,authcBasic,auchc,user是认证过滤器,

perms,roles,ssl,rest,port是授权过滤器

007-shiro与spring web项目整合【一】基础搭建的更多相关文章

  1. 010-shiro与spring web项目整合【四】缓存Ehcache

    一.Ehcache shiro每次授权都会通过realm获取权限信息,为了提高访问速度需要添加缓存,第一次从realm中读取权限数据,之后不再读取,这里Shiro和Ehcache整合. 1.添加Ehc ...

  2. 008-shiro与spring web项目整合【二】认证、授权、session管理

    一.认证 1.添加凭证匹配器 添加凭证匹配器实现md5加密校验. 修改applicationContext-shiro.xml: <!-- realm --> <bean id=&q ...

  3. 009-shiro与spring web项目整合【三】验证码、记住我

    一.验证码 1.自定义FormAuthenticationFilter 需要在验证账号和名称之前校验验证码 /** * * <p>Title: CustomFormAuthenticati ...

  4. (转)shiro权限框架详解06-shiro与web项目整合(下)

    http://blog.csdn.net/facekbook/article/details/54962975 shiro和web项目整合,实现类似真实项目的应用 web项目中认证 web项目中授权 ...

  5. (转) shiro权限框架详解06-shiro与web项目整合(上)

    http://blog.csdn.net/facekbook/article/details/54947730 shiro和web项目整合,实现类似真实项目的应用 本文中使用的项目架构是springM ...

  6. spring web项目中整合netty, akka

    spring web项目中整合netty, akka 本身的web项目仍然使用tomcat/jetty8080端口, 在org.springframework.beans.factory.Initia ...

  7. Spring与Web项目整合的原理

    引言: 在刚开始我们接触IOC时,我们加载并启用SpringIOC是通过如下代码手动加载 applicationContext.xml 文件,new出context对象,完成Bean的创建和属性的注入 ...

  8. 实战突击: Java Web项目整合开发(PDF)

    实战突击:  Java  Web项目整合开发(PDF)

  9. 【工具】Spring项目转化Spring Web项目插件

    前言 源于前一篇博文中提到,将Spring项目转化为Spring Web项目,发现添加项目文件和修改pom.xml文件等都是手动完成的,心想着开发一个Idea插件来自动化完成上面的过程,实现一键转化. ...

随机推荐

  1. c++的set_unexpected不起作用

    代码是从:http://www.cplusplus.com/referen ... /?kw=set_unexpected找的 // set_unexpected example #include & ...

  2. vim编码设置

    转载于:http://www.cnblogs.com/freewater/archive/2011/08/26/2154602.html vim 编码方式的设置和所有的流行文本编辑器一样,Vim 可以 ...

  3. python学习笔记3----正则表达式

    正则表达式(RE)是通过re模块来实现的. 字符匹配: --普通字符: *大多数字母和字符一般都会和自身匹配. --元字符:. ^ $ * + ? {}  [] \ | () []: 通常用来指定一个 ...

  4. 结构体sockadrr、sockaddr_in、in_addr的定义

    /* Internet address.  */typedef uint32_t in_addr_t;struct in_addr  {    in_addr_t s_addr;  };  typed ...

  5. spring+mybatis+javafx

    @Service用于标注业务层组件 @Controller用于标注控制层组件(如struts中的action) @Repository用于标注数据访问组件,即DAO组件. @Component泛指组件 ...

  6. 利用FFmpeg切割视频

    关键词:FFmpeg,seek,ss,t,to,搜索,定位 介绍 如果你想要从输入文件中切割一部分,需要用到ss选项. 快速定位 需要将ss放在输入文件的前面(即-i的前面) elesos1.jpg ...

  7. 第二百三十节,jQuery EasyUI,后台管理界面---后台管理

    jQuery EasyUI,后台管理界面---后台管理 一,admin.php,后台管理界面 <?php session_start(); if (!isset($_SESSION['admin ...

  8. Grodno 2015 (Urozero May 2015 Day 5) D Triangles

    给出$P(<=10^9)$, 求有多少个有序三元组$(a, b, c),\ gcd(a, b, c) = 1,\ a + b + c <= P$且以它们构成的三角形中存在某个角是另外一个角 ...

  9. Effective JavaScript Item 55 接受配置对象作为函数參数

    接受配置对象作为函数參数 尽管保持函数接受的參数的顺序非常重要,可是当函数可以接受的參数达到一定数量时.也会让用户非常头疼: var alert = new Alert(100, 75, 300, 2 ...

  10. 图表 Chart

    工作中,需要实现如下的图表,查阅了不少的资料,问了不少的人,下面对下图表的实现代码做下讲解. 实现代码: chart1.Series.Clear();//清空图表中的序列,图表中有默认的序列 //ch ...