`
andy_ghg
  • 浏览: 290559 次
  • 性别: Icon_minigender_1
  • 来自: 扬州
社区版块
存档分类
最新评论

MyEclipse中Spring Security 3.0.3无废话配置(第二章)。

    博客分类:
  • Java
阅读更多
上回说到数据库验证首先看以往的验证配置:
<authentication-manager>  
    <authentication-provider>  
        <user-service>  
            <user name="jimi" password="jimispassword" authorities="ROLE_USER, ROLE_ADMIN" />  
            <user name="bob" password="bobspassword" authorities="ROLE_USER" />  
        </user-service>  
    </authentication-provider>  
</authentication-manager>  

现在我们要用数据库来验证。
第一步:建立数据库
这里只用两张表即可解决问题,也许你看过很多建立五张到七张的,那是实际在项目中才这样做,我们做试验的话在这里只建立两张表:1.用户表2.资源表。
用户表四个字段:ID、USERNAME、PASSWORD、ROLE(权限)
资源表有三个字段:ID、资源路径、访问权限
资源路径就是一个URL地址,访问权限就是这个资源需要什么样子的权限才能访问。


第二步:权限提供
package cn.com.fri.security.supports;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.annotation.PostConstruct;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.access.SecurityConfig;
import org.springframework.security.web.FilterInvocation;
import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
import org.springframework.security.web.util.AntUrlPathMatcher;
import org.springframework.security.web.util.UrlMatcher;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import cn.com.fri.security.dao.interfaces.IAuthoritiesDAO;
import cn.com.fri.security.dao.interfaces.IResourcesDAO;
import cn.com.fri.security.vo.Authorities;
import cn.com.fri.security.vo.Resources;

/**
 * 
 * 此类在初始化时,应该取到所有资源及其对应角色的定义
 * 
 */
@Service("securityMetadataSource")
public class MyInvocationSecurityMetadataSource implements
		FilterInvocationSecurityMetadataSource {
	@Autowired
	private IAuthoritiesDAO authoritiesDAO;
	@Autowired
	private IResourcesDAO resourcesDAO;

	private UrlMatcher urlMatcher = new AntUrlPathMatcher();;
	private static Map<String, Collection<ConfigAttribute>> resourceMap = null;

	public MyInvocationSecurityMetadataSource() {
	}

	/**
	 * 在此处,将数据库中所有的资源以及对应的权限加入到内存中
	 */
	@PostConstruct
	public void loadResourceDefine() {
		resourceMap = new HashMap<String, Collection<ConfigAttribute>>();
		Collection<ConfigAttribute> atts = new ArrayList<ConfigAttribute>();
		System.out.println(authoritiesDAO);
		List<Authorities> auth = authoritiesDAO.findAll();
		for (Authorities au : auth) {
			ConfigAttribute ca = new SecurityConfig(au.getAuthorname());
			atts.add(ca);
		}
		List<Resources> res = resourcesDAO.findAll();
		for (Resources resources : res) {
			resourceMap.put(resources.getResourcesstring(), atts);
		}
		System.out.println("权限加载完毕");
	}

	// According to a URL, Find out permission configuration of this URL.
	@Transactional(readOnly = true)
	public Collection<ConfigAttribute> getAttributes(Object object)
			throws IllegalArgumentException {
		// guess object is a URL.
		String url = ((FilterInvocation) object).getRequestUrl();
		Iterator<String> ite = resourceMap.keySet().iterator();
		while (ite.hasNext()) {
			String resURL = ite.next();
			if (urlMatcher.pathMatchesUrl(url, resURL)) {
				return resourceMap.get(resURL);
			}
		}
		return null;
	}

	public boolean supports(Class<?> clazz) {
		return true;
	}

	public Collection<ConfigAttribute> getAllConfigAttributes() {
		return null;
	}

	public void setAuthoritiesDAO(IAuthoritiesDAO authoritiesDAO) {
		this.authoritiesDAO = authoritiesDAO;
	}

	public void setResourcesDAO(IResourcesDAO resourcesDAO) {
		this.resourcesDAO = resourcesDAO;
	}

}

找个类的作用就是在服务器启动的时候将存放在数据库表中的资源与访问权限加载到内存中去。

第三步:编写路径验证类:
package cn.com.fri.security.supports;

import java.util.Collection;
import java.util.Iterator;

import org.springframework.security.access.AccessDecisionManager;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.access.SecurityConfig;
import org.springframework.security.authentication.InsufficientAuthenticationException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.stereotype.Service;
@Service("myAccessDecisionManagerBean")
public class MyAccessDecisionManager implements AccessDecisionManager {

	public void decide(Authentication authentication, Object object,
			Collection<ConfigAttribute> configAttributes)
			throws AccessDeniedException, InsufficientAuthenticationException {
		if (configAttributes == null) {
			return;
		}
		
		Iterator<ConfigAttribute> ite = configAttributes.iterator();
		while (ite.hasNext()) {
			ConfigAttribute ca = ite.next();
			String needRole = ((SecurityConfig) ca).getAttribute();
			for (GrantedAuthority ga : authentication.getAuthorities()) {
				if (needRole.equals(ga.getAuthority())) { // ga is user's role.
					return;
				}
			}
		}
		throw new AccessDeniedException("no right");
	}

	public boolean supports(ConfigAttribute attribute) {
		// TODO Auto-generated method stub
		return true;
	}

	public boolean supports(Class<?> clazz) {
		return true;
	}

}

此类用户判断当前登录的用户是否有权限访问某个路径。而这里路径的访问权限就是从内存中取出来的。
第四步:登录验证:
package cn.com.fri.security.supports;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.GrantedAuthorityImpl;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import cn.com.fri.security.dao.interfaces.IUsersDAO;
import cn.com.fri.security.vo.Authorities;
import cn.com.fri.security.vo.CustomUser;
import cn.com.fri.security.vo.Users;

@Service("userDetailsService")
public class UserDetailsServiceImpl implements UserDetailsService {

	@Autowired
	private IUsersDAO dao;

	@Transactional(readOnly = true)
	public UserDetails loadUserByUsername(String username)
			throws UsernameNotFoundException, DataAccessException {
		System.out.println(username);
		Users user = dao.findByUsername(username).get(0);//此查询由自己去实现
		if (user == null)
			throw new UsernameNotFoundException("user not found");
		Collection<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();

		List<Authorities> auths = dao.findAutByUsername(username);//此查询由自己去实现如果用户表中已经包含了权限,就无需进行这一步操作了。
		System.out.println(">>>>>>获得的权限有:" + auths.size() + "个");
		for (Authorities a : auths) {
			GrantedAuthorityImpl authorityImpl = new GrantedAuthorityImpl(a
					.getAuthorname());
			authorities.add(authorityImpl);
		}
		CustomUser u = new CustomUser(username, user.getPsw(), user
				.getEnabled(), true, true, true, authorities);
		u.setUser(user);
		return u;
	}
}

在这个类中,用户一旦登录,我们就能获取到用户的权限,将用户权限放入到CustomUser中,然后返回这个CustomUser即可。CustomUser为继承自org.springframework.security.core.userdetails.User的一个类,继承的原因是为了让原来的User能够拥有更多的属性,例如用户的中文名称等等。里面的List<Authorities> auths = dao.findAutByUsername(username);这一步是因为我是按照七张表的结构去建立的,因此如果你只有两张表,这里完全可以省略。你甚至可以在这里写死(试验用)如下:
GrantedAuthorityImpl authorityImpl = new GrantedAuthorityImpl("ROLE_ADMIN");
authorities.add(authorityImpl);

第五步:配置SS3的XML文件:
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/security"
	xmlns:beans="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-3.0.xsd 
	http://www.springframework.org/schema/security 
	http://www.springframework.org/schema/security/spring-security-3.0.xsd">
	<http auto-config='true' access-denied-page="/common/403.jsp">
		<!-- 以下为不需要权限就能访问的资源**意思就是包括子目录也同样适用 -->
		<intercept-url pattern="/css/**" filters="none" />
		<intercept-url pattern="/app/**" filters="none" />
		<intercept-url pattern="/images/**" filters="none" />
		<intercept-url pattern="/swf/**" filters="none" />
		<intercept-url pattern="/login.jsp*" access="IS_AUTHENTICATED_ANONYMOUSLY" />
		<form-login login-page='/login.jsp' default-target-url="/index.do"
			always-use-default-target="true" />
		<!-- 配置退出登录 -->
		<logout invalidate-session="true" logout-url="/logout"
			logout-success-url="/login.jsp" />
		<session-management invalid-session-url="/error.html">
			<concurrency-control max-sessions="1"
				expired-url="/error.html" />
		</session-management>
		<!--
			配置登录验证,包括权限的启动都在这里:
		-->
		<custom-filter before="FILTER_SECURITY_INTERCEPTOR" ref="myFilter" />
	</http>
	
	<!-- 配置登录验证的类 -->
	<beans:bean id="daoAuthenticationProvider"
		class="org.springframework.security.authentication.dao.DaoAuthenticationProvider">
		<beans:property name="userDetailsService" ref="userDetailsService" />
	</beans:bean>

	<beans:bean id="authenticationManager"
		class="org.springframework.security.authentication.ProviderManager">
		<beans:property name="providers">
			<beans:list>
				<beans:ref local="daoAuthenticationProvider" />
			</beans:list>
		</beans:property>
	</beans:bean>
	
	<authentication-manager>
		<authentication-provider user-service-ref="userDetailsService">
		</authentication-provider>
	</authentication-manager>


	<!--
		一个自定义的filter,必须包含authenticationManager,accessDecisionManager,securityMetadataSource三个属性,
		我们的所有控制将在这三个类中实现,这里使用了annocation,所以ref后面的参数在XML配置中是没有的,详细看这三个类。
	-->
	<beans:bean id="myFilter"
		class="cn.com.fri.security.supports.MyFilterSecurityInterceptor">
		<beans:property name="authenticationManager" ref="authenticationManager" />
		<beans:property name="accessDecisionManager" ref="myAccessDecisionManagerBean" />
		<beans:property name="securityMetadataSource" ref="securityMetadataSource" />
	</beans:bean>

</beans:beans>


由于东西较多,所以再一开始的时候建议大家去下载官方的说明文档和中文翻译的说明文档。
在此我们的配置结束。这一部分虽然代码比较多,但是其实一点不复杂,仔仔细细的看一遍就会了。
分享到:
评论
6 楼 516816168 2011-08-19  
详细,不错啊
5 楼 mfx258 2011-06-13  
andy_ghg 写道
就是登录后根本没有进入到UserDetailsServiceImpl这个类是吗?

进入这个类了,下面是后台日志输出:
INFO : com.sywzsh.security.PawnUsersDetailsService - auths===[AUTH_AFTERLOGINWELCOME, AUTH_LOGIN, AUTH_NODE_MGR, AUTH_XTSZ_DEPT, AUTH_XTSZ_USER, AUTH_AFTERLOGINWELCOME, AUTH_LOGIN, AUTH_AFTERLOGINWELCOME, AUTH_XTSZ_DEPT, AUTH_XTSZ_USER, AUTH_NODE_MGR]
INFO : com.sywzsh.security.dao.SysUsersDao - 根据UserAccount查找SysUsers实例对象: admin

INFO : com.sywzsh.security.dao.SysUsersDao - 相匹配的SysUsers实例对象被找到!

问题是在这一步
public Collection<ConfigAttribute> getAttributes(Object object)  
            throws IllegalArgumentException {  
        // guess object is a URL.  
        String url = ((FilterInvocation) object).getRequestUrl();  
        log.info("url====="+url);
        Iterator<String> ite = resourceMap.keySet().iterator();  
        while (ite.hasNext()) {  
            String resURL = ite.next();  
            if (urlMatcher.pathMatchesUrl(url, resURL)) {  
                return resourceMap.get(resURL);  
            }  
        }  
        return null;  
    }  


其中:log.info("url====="+url);打印出的是/jsp/fail.jsp,这个链接是在security.xml中配置的认证失败跳转页面
<form-login login-page="/jsp/admin/login.jsp" login-processing-url="/topic/add"
			authentication-failure-url="/jsp/fail.jsp" default-target-url="/jsp/index.jsp" />

点登录按钮,应该判断/jsp/index.jsp是否有权限,不知道为什么直接就跳到失败页面了
4 楼 andy_ghg 2011-06-13  
就是登录后根本没有进入到UserDetailsServiceImpl这个类是吗?
首先看一下是否进入了这个类,并且成功调用了loadUserByUsername这个方法(此方法是UserDetailsService接口提供的)。

按理来说,点击登录之后是应该调用这个方法的。如果没有调用,你查看一下这里的配置是否正确:
	<!-- 配置登录验证的类 -->
	<beans:bean id="daoAuthenticationProvider"
		class="org.springframework.security.authentication.dao.DaoAuthenticationProvider">
<!--------注意这里------------>
		<beans:property name="userDetailsService" ref="userDetailsService" />
	</beans:bean>

	<beans:bean id="authenticationManager"
		class="org.springframework.security.authentication.ProviderManager">
		<beans:property name="providers">
			<beans:list>
				<beans:ref local="daoAuthenticationProvider" />
			</beans:list>
		</beans:property>
	</beans:bean>
	
	<authentication-manager>
<!--------注意这里------------>
		<authentication-provider user-service-ref="userDetailsService">
		</authentication-provider>
	</authentication-manager>

里面的ref是参考了UserDetailServiceImple的annocation:
@Service("userDetailsService")  
public class UserDetailsServiceImpl implements UserDetailsService {  
    //..............
}
3 楼 mfx258 2011-06-13  
我扩展了userDetails 代码如下
List<GrantedAuthority> auths = new ArrayList<GrantedAuthority>();
		
		//得到用户的权限
		auths = sysUsersDao.loadUserAuthoritiesByUserName( username );
		
		log.info("auths==="+auths);
		
		//根据用户名取得一个SysUsers对象,以获取该用户的其他信息。
		SysUsersBean user = sysUsersDao.findByUserName( username );
		log.info("user===="+user);
		return new SysUsers( user.getUserId(), user.getUserAccount(), user.getUserName(),
				 user.getUserPassword(),user.getUserDesc(), user.getEnabled(), user.getIssys(),
				 user.getUserDuty(), user.getUserDept(), 
				 new HashSet(0), true, true, true, auths);


如果未登录,直接跳到登陆页面,比如访问/jsp/admin/security/role.jsp,后台输出

INFO : com.sywzsh.security.PawnInvocationSecurityMetadataSourceService - getAttributes(Object)=========/jsp/admin/security/role.jsp
INFO : com.sywzsh.security.PawnAccessDecisionManagerService - decide(Authentication, Object, Collection<ConfigAttribute>) - start
INFO : com.sywzsh.security.PawnAccessDecisionManagerService - 正在访问的url是:FilterInvocation: URL: /jsp/admin/security/role.jsp
INFO : com.sywzsh.security.PawnAccessDecisionManagerService - needRole is:AUTH_XTSZ_USER
INFO : com.sywzsh.security.PawnAccessDecisionManagerService - 授权信息是:ROLE_ANONYMOUS

这个是正确的,但输入用户名和密码后,再点登录,默认应该跳到
default-target-url="/index.jsp"

但后台什么输出都没有,直接又回到登录页面了
2 楼 andy_ghg 2011-06-13  
mfx258 写道
您好,按照您的配置,启动没有问题,只是在登录时,点击登录后直接跳到验证失败页面,debug跟踪发现,InvocationSecurityMetadataSourceService中的getAttributes(Object object)方法传入的object值就是验证失败页面的url,还有什么地方需要配置吗?

你好,首先看一下UserDetailsServiceImpl这个类中的
   CustomUser u = new CustomUser(username, user.getPsw(), user  
                .getEnabled(), true, true, true, authorities);  

有没有执行到这里。并且里面的authorities是否包含了权限,既:
GrantedAuthorityImpl authorityImpl = new GrantedAuthorityImpl("ROLE_ADMIN");  
authorities.add(authorityImpl);  

有没有类似的代码?

如果有的话,你的数据库中的资源所需权限是否与之相等,例如:
URL                   ROLE
/index.jsp         ROLE_ADMIN


1 楼 mfx258 2011-06-12  
您好,按照您的配置,启动没有问题,只是在登录时,点击登录后直接跳到验证失败页面,debug跟踪发现,InvocationSecurityMetadataSourceService中的getAttributes(Object object)方法传入的object值就是验证失败页面的url,还有什么地方需要配置吗?

相关推荐

    施耐德PLC例程源码twidopid控制实列

    施耐德PLC例程源码twido pid 控制实列提取方式是百度网盘分享地址

    node-v19.2.0-darwin-arm64.tar.xz

    Node.js,简称Node,是一个开源且跨平台的JavaScript运行时环境,它允许在浏览器外运行JavaScript代码。Node.js于2009年由Ryan Dahl创立,旨在创建高性能的Web服务器和网络应用程序。它基于Google Chrome的V8 JavaScript引擎,可以在Windows、Linux、Unix、Mac OS X等操作系统上运行。 Node.js的特点之一是事件驱动和非阻塞I/O模型,这使得它非常适合处理大量并发连接,从而在构建实时应用程序如在线游戏、聊天应用以及实时通讯服务时表现卓越。此外,Node.js使用了模块化的架构,通过npm(Node package manager,Node包管理器),社区成员可以共享和复用代码,极大地促进了Node.js生态系统的发展和扩张。 Node.js不仅用于服务器端开发。随着技术的发展,它也被用于构建工具链、开发桌面应用程序、物联网设备等。Node.js能够处理文件系统、操作数据库、处理网络请求等,因此,开发者可以用JavaScript编写全栈应用程序,这一点大大提高了开发效率和便捷性。 在实践中,许多大型企业和组织已经采用Node.js作为其Web应用程序的开发平台,如Netflix、PayPal和Walmart等。它们利用Node.js提高了应用性能,简化了开发流程,并且能更快地响应市场需求。

    node-v15.12.0-darwin-x64.tar.xz

    Node.js,简称Node,是一个开源且跨平台的JavaScript运行时环境,它允许在浏览器外运行JavaScript代码。Node.js于2009年由Ryan Dahl创立,旨在创建高性能的Web服务器和网络应用程序。它基于Google Chrome的V8 JavaScript引擎,可以在Windows、Linux、Unix、Mac OS X等操作系统上运行。 Node.js的特点之一是事件驱动和非阻塞I/O模型,这使得它非常适合处理大量并发连接,从而在构建实时应用程序如在线游戏、聊天应用以及实时通讯服务时表现卓越。此外,Node.js使用了模块化的架构,通过npm(Node package manager,Node包管理器),社区成员可以共享和复用代码,极大地促进了Node.js生态系统的发展和扩张。 Node.js不仅用于服务器端开发。随着技术的发展,它也被用于构建工具链、开发桌面应用程序、物联网设备等。Node.js能够处理文件系统、操作数据库、处理网络请求等,因此,开发者可以用JavaScript编写全栈应用程序,这一点大大提高了开发效率和便捷性。 在实践中,许多大型企业和组织已经采用Node.js作为其Web应用程序的开发平台,如Netflix、PayPal和Walmart等。它们利用Node.js提高了应用性能,简化了开发流程,并且能更快地响应市场需求。

    毕业设计 一款家庭记账本.zip

    毕业设计 一款家庭记账本

    Apache-maven-3.9.6-bin.tar.gz 安装包

    本资源是apache-maven-3.9.6版本安装包,适用于 Mac 操作系统,内部包含 apache-maven-3.9.6-bin.tar.gz 和 安装步骤,仅需解压即可使用,非常方便快捷!

    机械设计4L斗式提升sw16可编辑非常好的设计图纸100%好用.zip

    机械设计4L斗式提升sw16可编辑非常好的设计图纸100%好用.zip

    计算机设计 - VB+access文档管理系统(系统+开题报告+LW+答辩),保证可靠运行,毕业生可参考,免费资源下载

    本项目旨在开发一个基于VB(Visual Basic)和Access数据库的文档管理系统。该系统的主要目标是提高文档管理的效率和准确性,以满足企事业单位对文档管理的日常需求。 系统采用VB作为前端开发工具,利用其友好的用户界面和强大的编程能力,为用户提供直观、易用的操作界面。同时,Access数据库作为后端存储,确保文档数据的安全性和稳定性。 在系统功能上,本系统实现了文档的上传、下载、修改、删除等基本操作,同时支持文档的分类管理、权限控制等高级功能。通过分类管理,用户可以方便地查找和定位所需文档;通过权限控制,系统可以确保不同用户只能访问其权限范围内的文档,从而保障文档的安全性。 此外,系统还具备数据备份和恢复功能,以防止因意外情况导致的数据丢失。同时,系统还提供了日志记录功能,便于管理员对系统操作进行监控和审计。 本项目的开发将极大地提高企事业单位的文档管理效率,降低管理成本,为企业的信息化建设提供有力支持。未来,我们还将根据用户需求,不断优化系统功能,提升用户体验。

    node-v16.6.0-linux-s390x.tar.xz

    Node.js,简称Node,是一个开源且跨平台的JavaScript运行时环境,它允许在浏览器外运行JavaScript代码。Node.js于2009年由Ryan Dahl创立,旨在创建高性能的Web服务器和网络应用程序。它基于Google Chrome的V8 JavaScript引擎,可以在Windows、Linux、Unix、Mac OS X等操作系统上运行。 Node.js的特点之一是事件驱动和非阻塞I/O模型,这使得它非常适合处理大量并发连接,从而在构建实时应用程序如在线游戏、聊天应用以及实时通讯服务时表现卓越。此外,Node.js使用了模块化的架构,通过npm(Node package manager,Node包管理器),社区成员可以共享和复用代码,极大地促进了Node.js生态系统的发展和扩张。 Node.js不仅用于服务器端开发。随着技术的发展,它也被用于构建工具链、开发桌面应用程序、物联网设备等。Node.js能够处理文件系统、操作数据库、处理网络请求等,因此,开发者可以用JavaScript编写全栈应用程序,这一点大大提高了开发效率和便捷性。 在实践中,许多大型企业和组织已经采用Node.js作为其Web应用程序的开发平台,如Netflix、PayPal和Walmart等。它们利用Node.js提高了应用性能,简化了开发流程,并且能更快地响应市场需求。

    gec6818cv1-20170407为核心板原理图 gec6818bv3为底板原理图

    gec6818cv1_20170407为核心板原理图 gec6818bv3为底板原理图

    node-v10.9.0.tar.xz

    Node.js,简称Node,是一个开源且跨平台的JavaScript运行时环境,它允许在浏览器外运行JavaScript代码。Node.js于2009年由Ryan Dahl创立,旨在创建高性能的Web服务器和网络应用程序。它基于Google Chrome的V8 JavaScript引擎,可以在Windows、Linux、Unix、Mac OS X等操作系统上运行。 Node.js的特点之一是事件驱动和非阻塞I/O模型,这使得它非常适合处理大量并发连接,从而在构建实时应用程序如在线游戏、聊天应用以及实时通讯服务时表现卓越。此外,Node.js使用了模块化的架构,通过npm(Node package manager,Node包管理器),社区成员可以共享和复用代码,极大地促进了Node.js生态系统的发展和扩张。 Node.js不仅用于服务器端开发。随着技术的发展,它也被用于构建工具链、开发桌面应用程序、物联网设备等。Node.js能够处理文件系统、操作数据库、处理网络请求等,因此,开发者可以用JavaScript编写全栈应用程序,这一点大大提高了开发效率和便捷性。 在实践中,许多大型企业和组织已经采用Node.js作为其Web应用程序的开发平台,如Netflix、PayPal和Walmart等。它们利用Node.js提高了应用性能,简化了开发流程,并且能更快地响应市场需求。

    c语言对对碰游戏源码.rar

    c语言对对碰游戏源码.rar

    python英文短文自动分词写入文本文件

    对一句话进行分词是指将这个句子拆解成一个个独立的词语或单词。分词是自然语言处理中的一个重要任务,它有助于理解文本的语义和结构。 以下是对对一句话分词的一些基本说明: 分词目的:分词的目的是将连续的文本流转化为离散的词语单元。通过分词,可以更好地理解句子的含义、提取关键信息和进行后续的文本分析。 中文分词:在中文分词中,目标是将一句话拆分成一个个独立的汉字词语。中文的特点是没有像英文那样明确的空格来区分单词,因此分词变得尤为重要。 英文分词:相比之下,英文分词相对简单,因为英文单词通常以空格作为分隔符。但仍然需要处理缩写、连字符和标点等特殊情况。

    2024-2030全球与中国钼圆靶市场现状及未来发展趋势.docx

    2024-2030全球与中国钼圆靶市场现状及未来发展趋势

    video cms 后台管理系统 可用作毕业设计.zip

    video cms 后台管理系统 可用作毕业设计

    旅行商问题的多种求解算法.zip

    旅行商问题: 利用模拟退火算法、遗传算法等解决旅行商问题。 因为用于解决TSP问题的算法有很多种,遂将其整合成一个代码框架。

    node-v13.8.0-linux-ppc64le.tar.xz

    Node.js,简称Node,是一个开源且跨平台的JavaScript运行时环境,它允许在浏览器外运行JavaScript代码。Node.js于2009年由Ryan Dahl创立,旨在创建高性能的Web服务器和网络应用程序。它基于Google Chrome的V8 JavaScript引擎,可以在Windows、Linux、Unix、Mac OS X等操作系统上运行。 Node.js的特点之一是事件驱动和非阻塞I/O模型,这使得它非常适合处理大量并发连接,从而在构建实时应用程序如在线游戏、聊天应用以及实时通讯服务时表现卓越。此外,Node.js使用了模块化的架构,通过npm(Node package manager,Node包管理器),社区成员可以共享和复用代码,极大地促进了Node.js生态系统的发展和扩张。 Node.js不仅用于服务器端开发。随着技术的发展,它也被用于构建工具链、开发桌面应用程序、物联网设备等。Node.js能够处理文件系统、操作数据库、处理网络请求等,因此,开发者可以用JavaScript编写全栈应用程序,这一点大大提高了开发效率和便捷性。 在实践中,许多大型企业和组织已经采用Node.js作为其Web应用程序的开发平台,如Netflix、PayPal和Walmart等。它们利用Node.js提高了应用性能,简化了开发流程,并且能更快地响应市场需求。

    file_1713787473983.zip

    file_1713787473983.zip

    node-v18.14.1-linux-armv7l.tar.xz

    Node.js,简称Node,是一个开源且跨平台的JavaScript运行时环境,它允许在浏览器外运行JavaScript代码。Node.js于2009年由Ryan Dahl创立,旨在创建高性能的Web服务器和网络应用程序。它基于Google Chrome的V8 JavaScript引擎,可以在Windows、Linux、Unix、Mac OS X等操作系统上运行。 Node.js的特点之一是事件驱动和非阻塞I/O模型,这使得它非常适合处理大量并发连接,从而在构建实时应用程序如在线游戏、聊天应用以及实时通讯服务时表现卓越。此外,Node.js使用了模块化的架构,通过npm(Node package manager,Node包管理器),社区成员可以共享和复用代码,极大地促进了Node.js生态系统的发展和扩张。 Node.js不仅用于服务器端开发。随着技术的发展,它也被用于构建工具链、开发桌面应用程序、物联网设备等。Node.js能够处理文件系统、操作数据库、处理网络请求等,因此,开发者可以用JavaScript编写全栈应用程序,这一点大大提高了开发效率和便捷性。 在实践中,许多大型企业和组织已经采用Node.js作为其Web应用程序的开发平台,如Netflix、PayPal和Walmart等。它们利用Node.js提高了应用性能,简化了开发流程,并且能更快地响应市场需求。

    node-v10.11.0.tar.xz

    Node.js,简称Node,是一个开源且跨平台的JavaScript运行时环境,它允许在浏览器外运行JavaScript代码。Node.js于2009年由Ryan Dahl创立,旨在创建高性能的Web服务器和网络应用程序。它基于Google Chrome的V8 JavaScript引擎,可以在Windows、Linux、Unix、Mac OS X等操作系统上运行。 Node.js的特点之一是事件驱动和非阻塞I/O模型,这使得它非常适合处理大量并发连接,从而在构建实时应用程序如在线游戏、聊天应用以及实时通讯服务时表现卓越。此外,Node.js使用了模块化的架构,通过npm(Node package manager,Node包管理器),社区成员可以共享和复用代码,极大地促进了Node.js生态系统的发展和扩张。 Node.js不仅用于服务器端开发。随着技术的发展,它也被用于构建工具链、开发桌面应用程序、物联网设备等。Node.js能够处理文件系统、操作数据库、处理网络请求等,因此,开发者可以用JavaScript编写全栈应用程序,这一点大大提高了开发效率和便捷性。 在实践中,许多大型企业和组织已经采用Node.js作为其Web应用程序的开发平台,如Netflix、PayPal和Walmart等。它们利用Node.js提高了应用性能,简化了开发流程,并且能更快地响应市场需求。

    node-v14.0.0-darwin-x64.tar.xz

    Node.js,简称Node,是一个开源且跨平台的JavaScript运行时环境,它允许在浏览器外运行JavaScript代码。Node.js于2009年由Ryan Dahl创立,旨在创建高性能的Web服务器和网络应用程序。它基于Google Chrome的V8 JavaScript引擎,可以在Windows、Linux、Unix、Mac OS X等操作系统上运行。 Node.js的特点之一是事件驱动和非阻塞I/O模型,这使得它非常适合处理大量并发连接,从而在构建实时应用程序如在线游戏、聊天应用以及实时通讯服务时表现卓越。此外,Node.js使用了模块化的架构,通过npm(Node package manager,Node包管理器),社区成员可以共享和复用代码,极大地促进了Node.js生态系统的发展和扩张。 Node.js不仅用于服务器端开发。随着技术的发展,它也被用于构建工具链、开发桌面应用程序、物联网设备等。Node.js能够处理文件系统、操作数据库、处理网络请求等,因此,开发者可以用JavaScript编写全栈应用程序,这一点大大提高了开发效率和便捷性。 在实践中,许多大型企业和组织已经采用Node.js作为其Web应用程序的开发平台,如Netflix、PayPal和Walmart等。它们利用Node.js提高了应用性能,简化了开发流程,并且能更快地响应市场需求。

Global site tag (gtag.js) - Google Analytics