ejb jsf jpa_完整的WebApplication JSF EJB JPA JAAS –第1部分

ejb jsf jpa

这篇文章将是迄今为止我博客中最大的一篇文章! 我们将看到完整的Web应用程序。 最新的技术(直到今天)都将完成,但是我将给出一些提示以显示如何使本文章适应较旧的技术。

在本文的结尾,您将找到要下载的源代码。 您可以根据需要使用它。 只需转到最后一页并进行下载。 \ o /

如果您下载了代码但不了解某些内容,则在本文中,我将解释代码中找到的每个详细信息。 只需阅读此帖子中想要的主题即可。

我将在本文中列出以下技术:

  • JSF 2.0 Mojarra –使用ManagedBeans作为RequestScope和SessionScope。
  • 消息国际化–包含我们系统所有消息的文件; 轻松翻译您的页面。
  • 将作为库导入的默认CSS文件。
  • EJB 3 –我们的DAO和Façades将是@Stateless。
  • 通用DAO –通用DAO,它将采取CRUD动作使我们的生活更轻松。
  • JPA 2 –在数据库中映射我们的类
  • JAAS –控制登录和用户对页面的访问。
  • MVC –我将使用此模式进行少量修改。
  • Postgres作为数据库,但我还将展示如何将您的应用设置为MySQL。

我不会使用TDD – JUnit测试我们的View / Model / Classes,但是在以下链接中,您可以看到一种使用JUnit测试您的ManagedBeans的技术: 具有HSQLDB,JPA和Hibernate的JUnit 。

我们将使用的工具:

  • Eclipse Indigo – http://www.eclipse.org/downloads/packages/eclipse-ide-java-ee-developers/indigor
  • 我将使用JBoss 7(此博客的某些读者问我了)– http://download.jboss.org/jbossas/7.0/jboss-as-7.0.2.Final/jboss-as-7.0.2.Final。 .zip的版本是: JBoss 7 Everything(未通过Java EE6认证)
  • Indigo JBoss工具(里程碑版本)– https://www.jboss.org/tools/download/dev.html如果您不知道如何在本文中安装JBoss工具,我将展示如何( 使用JAAS进行用户登录验证和JSF )。 请注意,在这篇文章中,我将展示如何安装到另一个eclipse版本,但是区别在于URL。 使用此URL代替上面链接中使用的URL: http : //download.jboss.org/jbosstools/updates/development/indigo/
  • 我将使用Postgres数据库,但您可以使用所需的任何数据库。 您只需要下载数据库和JDBC驱动程序。 在这里,您可以下载最新的Postgres JDBC: http : //jdbc.postgresql.org/download.html ; 到目前为止,最新版本是4: http : //jdbc.postgresql.org/download/postgresql-9.1-901.jdbc4.jar 。

这篇文章将有几页; 这第一页只是为了显示今天帖子的技术细节。

我不会编写代码来连接模型/ DAO,只是为了节省空间。 请记住,您应该始终对接口进行编码( 设计模式-策略 )

在继续之前,请确保按照正确的顺序安装了JBoss工具和JBoss 7。

商业模式

让我们创建将容纳我们的系统业务的EJB项目。

点击“ 完成 ”按钮。

让我们创建将在“ com”包中的User和Dog类。 它将具有以下代码:

package com.model;import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.NamedQuery;
import javax.persistence.Table;@Entity
@Table(name = 'USERS')
@NamedQuery(name='User.findUserByEmail', query='select u from User u where u.email = :email')
public class User {public static final String FIND_BY_EMAIL = 'User.findUserByEmail';@Id@GeneratedValue(strategy=GenerationType.AUTO)private int id;@Column(unique = true)private String email;private String password;private String name;private String role;public int getId() {return id;}public void setId(int id) {this.id = id;}public String getEmail() {return email;}public void setEmail(String email) {this.email = email;}public String getPassword() {return password;}public void setPassword(String password) {this.password = password;}public String getName() {return name;}public void setName(String name) {this.name = name;}public String getRole() {return role;}public void setRole(String role) {this.role = role;}@Overridepublic int hashCode() {return getId();}@Overridepublic boolean equals(Object obj) {if(obj instanceof User){User user = (User) obj;return user.getEmail().equals(getEmail());}return false;}
}
package com.model;import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;@Entity
@Table(name = 'DOGS')
public class Dog {@Id@GeneratedValue(strategy = GenerationType.AUTO)private int id;private String name;private double weight;public int getId() {return id;}public void setId(int id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public double getWeight() {return weight;}public void setWeight(double weight) {this.weight = weight;}@Overridepublic int hashCode() {return getId();}@Overridepublic boolean equals(Object obj) {if(obj instanceof Dog){Dog dog = (Dog) obj;return dog.getId() == getId();}return false;}
}

关于上面的代码:

  • User类具有一个名为“ role”的字段,该字段将存储用户的角色级别。 我将其创建为一个字段,并将所有数据保留在同一表中,以便于理解。 如果您需要有关JAAS的更多详细信息,可以在这篇文章中: 使用JAAS和JSF进行用户登录验证 。
  • 我将让JPA处理表ID代。 如果要更改ID的创建方式,可以查看以下文章以了解如何执行: JPA SequenceGenerator , JPA TableGenerator –简单Primay密钥 。
  • 该电子邮件将是唯一的; 这将是登录标识符。
  • 注意,要声明为Entity的类,只需要以下注释:“ @Entity”和“ @Id”。 该类不需要实现Serializable接口。

商业– DAO

我将使用通用DAO进行基本的CRUD操作,而其他两个DAO:一个用于User,另一个用于Dog。 理解它的用法将非常容易:

package com.dao;import java.util.List;
import java.util.Map;
import java.util.Map.Entry;import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import javax.persistence.criteria.CriteriaQuery;public abstract class GenericDAO<T> {private final static String UNIT_NAME = 'CrudPU';@PersistenceContext(unitName = UNIT_NAME)private EntityManager em;private Class<T> entityClass;public GenericDAO(Class<T> entityClass) {this.entityClass = entityClass;}public void save(T entity) {em.persist(entity);}public void delete(T entity) {T entityToBeRemoved = em.merge(entity);em.remove(entityToBeRemoved);}public T update(T entity) {return em.merge(entity);}public T find(int entityID) {return em.find(entityClass, entityID);}// Using the unchecked because JPA does not have a// em.getCriteriaBuilder().createQuery()<T> method@SuppressWarnings({ 'unchecked', 'rawtypes' })public List<T> findAll() {CriteriaQuery cq = em.getCriteriaBuilder().createQuery();cq.select(cq.from(entityClass));return em.createQuery(cq).getResultList();}// Using the unchecked because JPA does not have a// ery.getSingleResult()<T> method@SuppressWarnings('unchecked')protected T findOneResult(String namedQuery, Map<String, Object> parameters) {T result = null;try {Query query = em.createNamedQuery(namedQuery);// Method that will populate parameters if they are passed not null and emptyif (parameters != null && !parameters.isEmpty()) {populateQueryParameters(query, parameters);}result = (T) query.getSingleResult();} catch (Exception e) {System.out.println('Error while running query: ' + e.getMessage());e.printStackTrace();}return result;}private void populateQueryParameters(Query query, Map<String, Object> parameters) {for (Entry<String, Object> entry : parameters.entrySet()) {query.setParameter(entry.getKey(), entry.getValue());}}
}
package com.dao;import javax.ejb.Stateless;import com.model.Dog;@Stateless
public class DogDAO extends GenericDAO<Dog> {public DogDAO() {super(Dog.class);}
}
package com.dao;import java.util.HashMap;
import java.util.Map;import javax.ejb.Stateless;import com.model.User;@Stateless
public class UserDAO extends GenericDAO<User> {public UserDAO() {super(User.class);}public User findUserByEmail(String email){Map<String, Object> parameters = new HashMap<String, Object>();parameters.put('email', email);  return super.findOneResult(User.FIND_BY_EMAIL, parameters);}
}

关于上面的代码:

  • 我隐藏了一些警告,因为JPA代码尚未“理解”泛型。
  • “ findOneResult”方法具有受保护的访问权限,只是为了防止其他类进行外部访问; 正如我们在UserDAO中看到的那样,此方法需要逻辑来填充参数。
  • GenericDAO类具有完整的CRUD方法以及给定NamedQuery返回单个对象的方法。
  • UserDAO类具有仅属于该类的方法(findUserByEmail)。 但是它通过继承具有所有CRUD方法。 通过这种DAO模式,我们获得了更灵活的代码。
  • DogDAO中没有方法,只有CRUD方法。 您可以毫无问题地实现类中的任何方法。
  • 可以使用一种方法“ entityManager.merge()”代替使用“保存”方法,而使用其他方法“更新”对象。 您将得到相同的结果,但需要注意Cascade选项。
  • 我没有使用接口,因为EJB 3.1允许我们拥有无接口的无状态本地会话Bean。 如果您使用的是较旧的EJB版本,则需要实现一个接口(如何在Façades页面上的这篇文章中看到如何使用接口实现EJB)。 我不会为了节省空间而使用我的DAO /模型接口进行开发。 记住:“总是编程到接口”( 设计模式–策略 )。
  • 如果使用JBoss 4.2,则可以使用org.jboss.annotation.ejb.LocalBinding或org.jboss.annotation.ejb.RemoteBinding注释; 在此注释中,您可以编写将由EJB映射和引用的名称。

商业–外墙

我将创建Façades,它将成为View和DAO之间的“桥梁”。 在Façade中,我们将保留所有业务规则,仅将DAO保留为“数据库”功能/事务,例如CRUD和查询。

让我们看看我们的类UserFacade和DogFacade将如何:

package com.facade;import java.util.List;import javax.ejb.Local;import com.model.Dog;@Local
public interface DogFacade {public abstract void save(Dog dog);public abstract Dog update(Dog dog);public abstract void delete(Dog dog);public abstract Dog find(int entityID);public abstract List<Dog> findAll();
}
package com.facade;import java.util.List;import javax.ejb.EJB;
import javax.ejb.Stateless;import com.dao.DogDAO;
import com.model.Dog;@Stateless
public class DogFacadeImp implements DogFacade {@EJBprivate DogDAO dogDAO;@Overridepublic void save(Dog dog) {isDogWithAllData(dog);dogDAO.save(dog);}@Overridepublic Dog update(Dog dog) {isDogWithAllData(dog);return dogDAO.update(dog);}@Overridepublic void delete(Dog dog) {dogDAO.delete(dog);}@Overridepublic Dog find(int entityID) {return dogDAO.find(entityID);}@Overridepublic List<Dog> findAll() {return dogDAO.findAll();}private void isDogWithAllData(Dog dog){boolean hasError = false;if(dog == null){hasError = true;}if (dog.getName() == null || ''.equals(dog.getName().trim())){hasError = true;}if(dog.getWeight() <= 0){hasError = true;}if (hasError){throw new IllegalArgumentException('The dog is missing data. Check the name and weight, they should have value.');}}
}
package com.facade;import javax.ejb.Local;import com.model.User;@Local
public interface UserFacade {public User findUserByEmail(String email);
}
package com.facade;import javax.ejb.EJB;
import javax.ejb.Stateless;import com.dao.UserDAO;
import com.model.User;@Stateless
public class UserFacadeImp implements UserFacade {@EJBprivate UserDAO userDAO;public User findUserByEmail(String email) {return userDAO.findUserByEmail(email);}
}

关于上面的代码:

  • DogFacadeImp类完成了从视图保护DogDAO的所有工作。 它可能具有业务规则,并且如果某些数据丢失或任何其他业务规则已被破坏,则避免访问数据库。
  • UserFacade只有一种方法,因为在这篇文章中我们将不会有一个User Crud。 如果视图未在HttpSession中找到,则Bean将仅搜索用户。
  • 如果使用JBoss 4.2,则可以使用org.jboss.annotation.ejb.LocalBinding或org.jboss.annotation.ejb.RemoteBinding注释; 在此注释中,您可以编写将由EJB映射和引用的名称。
  • 我在DogFacadeImp中进行验证,以确保Dog仅具有有效数据。 请记住,每个人都可以向您发送无效数据,并且您的视图验证可能无法按您期望的那样工作。 您的应用程序的数据非常重要,仔细检查总是值得的。

接口用@Local注释,但我记得您这个注释是可选的。 如果不写@Local批注,则服务器将默认假定您的EJB是本地的。

业务–数据源(按模块)

我们还需要设置数据源。

最初,我尝试通过遵循本教程http://community.jboss.org/wiki/JBossAS7-DatasourceConfigurationForPostgresql创建数据源(我确实像其他任何人一样都遵循教程),但是在使用Java进行部署后开始出现一些错误EJB和JBoss找不到Postgres jar。

如果您使用的是JBoss 6或它下面的任何版本,则无需创建模块。 只需将文件放在“ default / lib”文件夹中即可。 如果您对设置数据源有任何疑问,请在JBoss 6或它下面的其他版本中显示如何执行此操作: 使用JAAS和JSF进行用户登录验证 。

让我们创建Postgres模块。 在JBoss 7内创建目录: YOUR_JBOSS / modules / org / postgresql / main ”。 将jar复制到创建的目录并创建一个名为“ module.xml”的文件; 将下面的代码复制到“ module.xml”文件中:

<?xml version='1.0' encoding='UTF-8'?>
<module xmlns='urn:jboss:module:1.0' name='org.postgresql'><resources><resource-root path='postgresql-9.1-901.jdbc4.jar'/></resources><dependencies><module name='javax.api'/></dependencies>
</module>

请注意,在“ module.xml”文件中,我们编写了jar文件名,该名称必须与Postgres jar文件名相同。

要创建MySQL模块,请创建以下文件夹 YOUR_JBOSS / modules / com / mysql / main 。 将jar复制到创建的目录并创建一个名为“ module.xml”的文件; 将下面的代码复制到“ module.xml”文件中:

<?xml version='1.0' encoding='UTF-8'?><!--~ JBoss copyrights~ http://community.jboss.org/wiki/DataSourceConfigurationInAS7--><module xmlns='urn:jboss:module:1.0' name='com.mysql'><resources><resource-root path='mysql-connector-java-5.1.15.jar'/></resources><dependencies><module name='javax.api'/></dependencies>
</module>

让我们编辑文件“ YOUR_JBOSS / standalone / configuration / standalone.xml ”。 在键“ <datasources>”内,添加以下代码:

<datasources><!-- Add this config: begin --><datasource jndi-name='CrudDS' pool-name='CrudDS_Pool' enabled='true' jta='true' use-java-context='true' use-ccm='true'><connection-url>jdbc:postgresql://localhost:5432/CrudDB</connection-url><driver-class>org.postgresql.Driver</driver-class><driver>postgresql-jdbc4</driver><pool><min-pool-size>2</min-pool-size><max-pool-size>20</max-pool-size><prefill>true</prefill><use-strict-min>false</use-strict-min><flush-strategy>FailingConnectionOnly</flush-strategy></pool><security><user-name>postgres</user-name><password>postgres</password></security><validation><check-valid-connection-sql>SELECT 1</check-valid-connection-sql><validate-on-match>false</validate-on-match><background-validation>false</background-validation><use-fast-fail>false</use-fast-fail></validation></datasource><!-- Add this config: end --><drivers><!-- Add this config: begin --><driver name='postgresql-jdbc4' module='org.postgresql'/><!-- Add this config: end --></drivers>

要使用MySQL配置数据源,请看这里:
http://community.jboss.org/wiki/DataSourceConfigurationInAS7

业务– XML配置

让我们看看我们的persistence.xml将会如何(该文件必须在文件夹src / META-INF内):

<?xml version='1.0' encoding='UTF-8'?>
<persistence version='1.0' xmlns='http://java.sun.com/xml/ns/persistence' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xsi:schemaLocation='http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd'><persistence-unit name='CrudPU' transaction-type='JTA'><provider>org.hibernate.ejb.HibernatePersistence</provider><jta-data-source>java:/CrudDS</jta-data-source><properties><property name='hibernate.hbm2ddl.auto' value='update'/></properties></persistence-unit>
</persistence>

我们有一个非常简单的代码; 它仅指向数据源,并带有使用“ update”生成所有数据库表的选项。

将EJB项目添加到JBoss。

在Postgres中创建数据库并启动JBoss; 启动后,JPA将创建表。

查看下面的图片,查看JPA为我们创建的表/序列。

在WEB-INF文件夹中创建一个名为“ jboss-web.xml”的文件,并在其中编写以下代码:

<?xml version='1.0' encoding='UTF-8'?><jboss-web><!-- URL to access the web module --><context-root>CrudJSF</context-root><!-- Realm that will be used --><security-domain>java:/jaas/CrudJSFRealm</security-domain>
</jboss-web>

在上面的文件中,我们设置了应用程序将使用的领域。 让我们将用户插入将通过JAAS进行登录的数据库中(如果您想查看有关JAAS的更多详细信息,可以在此处查看: 使用JAAS和JSF的用户登录验证 )。 我不会获得JAAS详细信息,因为您可以在上一个链接中找到详细的每个步骤。

在下面的图像中看到在数据库中手动插入的数据(您应该执行相同的操作):

继续本教程的第二部分 。

参考: uaiHebert博客上来自我们的JCG合作伙伴 Hebert Coelho的完整WebApplication JSF EJB JPA JAAS 。


翻译自: https://www.javacodegeeks.com/2012/06/full-webapplication-jsf-ejb-jpa-jaas.html

ejb jsf jpa

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/354668.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Jzoj4782 Math

若一个数x是平方数&#xff0c;则d(x)为平方数 所以就是要考虑有多少对i*j为平方数 我们假设&#xff0c;ip*k^2&#xff0c;那么&#xff0c;jp*q^2时&#xff0c;i*j为平方数&#xff08;p不含平方因子&#xff0c;k&#xff0c;q为正整数&#xff09; 所以&#xff0c;我们对…

前端暗黑模式,你了解多少

关于使用越来越多的前端暗黑模式&#xff0c;手机的app或网站都将支持暗黑模式逐渐成为一种规范&#xff0c;这样做的目的是什么呢&#xff1f;从我最初的理解是为了在黑暗的环境下屏幕上阅读的体验考虑&#xff0c;但是看了文摘却有另一种意义。暗黑模式究竟能不能起到省电的作…

两全其美的

使用抽象文档模式的类型安全视图 您如何组织对象&#xff1f; 在本文中&#xff0c;我将介绍一种模式&#xff0c;该模式以无类型的方式在您的系统中组织所谓的名词类&#xff0c;然后使用特征公开数据的类型化视图。 这使得只需少量的牺牲就可以在Java之类的语言中获得JavaScr…

Windows内核函数

字符串处理 在驱动中一般使用的是ANSI字符串和宽字节字符串&#xff0c;在驱动中我们仍然可以使用C中提供的字符串操作函数&#xff0c;但是在DDK中不提倡这样做&#xff0c;由于C函数容易导致缓冲区溢出漏洞&#xff0c;针对字符串的操作它提供了一组函数分别用来处理ANSI字符…

前端应该关注的2021年UI设计趋势

UI设计趋势几乎每年都在发生变化&#xff0c;变化的原因是人们的审美在变导致的&#xff0c;还是设计越来越人性化。市场上是谁在主导设计趋势&#xff1f;其中原因不得而知&#xff0c;我们先看看究竟有哪些变化&#xff1a;1. 3D插图&#xff08;依然流行&#xff09;3D图像将…

如何让你在开发者工具中查看源代码有语法高亮和暗黑主题的效果

如何让你在Chrome浏览器开发者工具中查看源代码的时候&#xff0c;和在代码编辑器中有同样的代码语法高亮的效果&#xff0c;而且还是深色主题&#xff0c;如果你是深色主题的爱好者就更合你意了。国外的美女开发者为你实现了这样功能的浏览器拓展&#xff0c;她的Github主页&a…

“太空语言”JavaScript编码标准规范指南

喷气推进实验室是 美国国家航空航天局的科研机构。 该实验室JPL开发大部分的软件是用在无人深度太空和其他行星探测的领域。他们拥有著名的 好奇号火星探测器 和 旅行者号探测器 。已经离开太阳系25年&#xff0c;仍然在飞行并提供科学信息。高水平的自动化和长期的任务导致了对…

如何在JUnit 5中替换规则

最近发布的JUnit 5&#xff08;又名JUnit Lambda&#xff09; Alpha版本引起了我的兴趣&#xff0c;在浏览文档时&#xff0c;我注意到规则以及跑步者和阶级规则都消失了。 根据文档&#xff0c;这些部分竞争的概念已被单个一致的扩展模型取代。 多年来&#xff0c; Frank和我…

微页面设计开发指南

一、目标实现左侧&#xff1a;为可用的组件列表&#xff0c;可拖动任一组件到中间的预览区域中间&#xff1a;为页面预览效果页面&#xff0c;选中任一组件&#xff0c;可在右侧进行参数配置右侧&#xff1a;为组件的参数配置&#xff08;选中中间的组件时出现&#xff09;&…

商城商品购买数量增减的完美JS效果

商城商品购买数量增减的完美JS效果 近期在开发一个地方O2O租书项目&#xff0c;使用ASP.NET MVC技术&#xff0c;其中在图书详情页&#xff0c;用户可以输入借阅的数量&#xff0c;这里使用了js来控制数量的增减和校验。 数量一定是数字 点击增减按钮的时候要能自动加1或减1 …

这款插件让你在VSCode上也能答题背单词

在VSCode上也可以在线答题了&#xff0c;插件市场上线了一款答题的插件&#xff0c;免去了去其它网站或者软件的烦恼&#xff0c;代码写累了&#xff0c;随手打开答题功能&#xff0c;换换脑子&#xff0c;或者熟悉两个单词&#xff0c;程序员的别样休闲时光&#xff0c;哈哈&a…

使用Java 8在地图上流式传输

在本文中&#xff0c;我将向您展示如何在标准Java映射上有效地实现Speedment Open Source流&#xff0c;并将Stream接口扩展为MapStream&#xff01; 即使在复杂的情况下&#xff0c;此添加将使保持流的具体性和可读性变得更加容易。 希望这将允许您继续流式传输而不会过早收集…

如何使用python给PDF文件加水印

Python作为编程界最火的语言&#xff0c;能做的事几乎你能想到的它都能干&#xff0c;就连抢茅台都可以&#xff0c;还有什么不行&#xff1f;&#xff01;Python作为脚本编程语言&#xff0c;可以做很多事情。使用Python&#xff0c;你可以轻松地给pdf加上水印。 你可以使用名…

搭建一个redis高可用系统

一、单个实例 当系统中只有一台redis运行时&#xff0c;一旦该redis挂了&#xff0c;会导致整个系统无法运行。 单个实例二、备份 由于单台redis出现单点故障&#xff0c;就会导致整个系统不可用&#xff0c;所以想到的办法自然就是备份&#xff08;一般工业界认为比较安全的备…

SSH连接远程服务器,本地known_hosts文件记录了什么

今天工作时&#xff0c;使用ssh命令远程连接公司的本地服务器时&#xff0c;突然出现以下错误bash-3.2$ ssh argus192.168.200.8 WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY! Someone could be eavesdroppin…

“全人类的知识宝藏”维基百科迎来了20岁的生日!

维基百科从一个伟大的想法开始&#xff0c;与无数的像你像我一样的阅读者&#xff0c;创作者&#xff0c;捐赠者和粉丝经历了互联网的20年&#xff0c;今天让我们一起为这个属于所有互联网人的成果庆祝一次生日。值此20周年特地为它做了一个主页&#xff1a;https://wikimediaf…

转:智能音箱市场深度报告:怎么大家都在抢这个两亿小蛋糕?

原文链接&#xff1a;http://www.sohu.com/a/199335366_115978 智能音箱是今年最热的智能硬件项目之一。目前&#xff0c;智能音箱已经有了比较成熟的技术方案和模式思路&#xff0c;但消费市场似乎依然秉持着比较谨慎的态度。智能音箱市场上的主流产品都有什么思路&#xff1f…

Tailwindcss尤大神都fork了,是未来的趋势?

最近Tailwindcss频繁出现在我的视野里&#xff0c;从单词拼写中看&#xff0c;多多少少与css有点关系。近几年是JS框架大行其道&#xff0c;CSS方面少有新的框架出现。昨天突然看到尤大神在Github上的动态&#xff0c;fork了该项目&#xff0c;看来马上要火的节奏啊&#xff01…

JUnit 5 –架构

现在我们知道如何设置JUnit 5并使用它编写一些测试 &#xff0c;下面让我们看一下。 在本文中&#xff0c;我们将讨论JUnit 5架构以及采用这种方式的原因。 总览 这篇文章是有关JUnit 5的系列文章的一部分&#xff1a; 设定 基本 建筑 条件 注射 … JUnit 4 忽略Hamcre…

前端程序员书桌上不可缺少的CSS书籍

作为前端&#xff0c;CSS不仅要会&#xff0c;而且要精通&#xff0c;随着各种浏览器规范参差不齐和网页交互多元化的趋势越来越复杂&#xff0c;前端程序员必须要将CSS基础知识打牢。由于现在的框架越来越多&#xff0c;导致很大一部分程序员的工作只是拿着现成的组件布局&…