一、信息化基本知识
(一)信息化的定义
信息化是指充分利用信息技术,开发利用信息资源,促进信息交流和知识共享,提高经济增长质量,推动社会全面进步的过程。它涵盖了社会各个领域,包括经济、政治、文化、教育等。
(二)信息化的特征
- 数字化
- 这是信息化的基础特征。信息以数字形式存储、处理和传输。例如,在企业中,财务数据不再以纸质账本形式存在,而是通过会计软件以数字形式记录在计算机系统中。这种数字化使得信息的处理更加高效,计算精度更高,而且便于存储和检索。
- 网络化
- 信息通过网络进行快速传播和共享。互联网是网络化的典型代表。人们可以通过互联网获取全球范围内的信息,如新闻、学术资料等。企业内部的局域网也使得员工之间能够方便地共享文件、协同工作。网络化打破了时间和空间的限制,极大地提高了信息交流的效率。
- 智能化
- 信息化发展到高级阶段,会体现出智能化的特征。例如,智能客服系统能够通过自然语言处理技术理解用户的问题,并自动给出准确的回答。智能家居系统可以根据用户的习惯自动调节室内温度、灯光等设备。智能化是通过人工智能、机器学习等技术实现的,它使得信息系统能够像人类一样对信息进行分析和决策。
(三)信息化的作用
- 提高生产效率
- 在制造业中,通过引入信息化技术,如自动化生产线控制系统,可以精确地控制生产流程,减少人工操作的误差。例如,汽车制造企业利用机器人进行零部件的焊接和装配,生产效率大幅提高,产品质量也更加稳定。
- 优化管理决策
- 信息化为管理者提供了丰富的数据支持。企业资源规划(ERP)系统可以整合企业的财务、采购、销售等各个部门的数据。管理者可以通过数据分析工具,对这些数据进行挖掘和分析,从而做出更加科学的决策。例如,通过分析销售数据,企业可以预测市场需求,合理安排生产计划。
- 促进社会服务创新
- 在医疗领域,信息化推动了远程医疗的发展。患者可以通过视频会诊系统向外地的专家咨询病情,专家可以查看患者的电子病历,给出诊断意见。在教育领域,信息化使得在线教育成为可能,学生可以通过互联网学习各种课程,打破了传统教育的时空限制。
二、信息系统开发基本知识
(一)信息系统的定义
信息系统是由计算机硬件、软件、数据、人员和规程组成的,能够对数据进行收集、存储、处理、传输和检索,以支持组织的决策、协调、控制和管理的系统。
(二)信息系统开发方法
- 生命周期法
- 这是一种传统的信息系统开发方法。它将信息系统开发过程划分为多个阶段,包括系统规划、系统分析、系统设计、系统实施和系统维护。
-
- 系统规划阶段:主要是确定系统开发的目标和范围。例如,一个企业想要开发一个客户关系管理系统(CRM),在规划阶段就要明确该系统要实现哪些功能,如客户信息管理、销售机会跟踪等,以及系统的开发预算和时间安排。
-
- 系统分析阶段:主要是对系统的需求进行详细分析。通过与用户沟通,收集用户对系统的功能需求和性能需求。例如,在开发一个图书馆管理系统时,要分析图书借阅流程、图书检索需求等。
-
- 系统设计阶段:根据系统分析的结果,设计系统的结构和模块。包括数据库设计、系统架构设计等。例如,设计一个电商平台系统,要确定数据库中商品表、用户表、订单表等的结构,以及系统的前端界面和后端服务的架构。
-
- 系统实施阶段:主要是将设计好的系统付诸实践。包括程序编码、系统测试等环节。在测试阶段,要对系统的功能进行严格的测试,确保系统能够正常运行。例如,开发一个手机应用程序,要进行功能测试、性能测试和兼容性测试。
-
- 系统维护阶段:系统上线后,要进行维护。包括对系统进行升级、修复漏洞、优化性能等。例如,随着业务的发展,系统可能需要增加新的功能,或者对现有功能进行优化。
- 原型法
- 原型法是一种快速开发方法。它首先根据用户的基本需求,快速开发一个原型系统。这个原型系统是一个简单的、能够体现系统基本功能的版本。然后通过用户对原型系统的反馈,对系统进行修改和完善。
- 例如,开发一个简单的在线投票系统,开发人员可以先开发一个只有投票功能的原型系统,让用户进行试用。用户可能会提出一些意见,如界面不够美观、投票结果统计不够详细等。根据这些反馈,开发人员对原型系统进行改进,逐步完善系统。
- 面向对象方法
- 这种方法将现实世界中的事物抽象为对象。对象具有属性和方法。例如,在开发一个学校管理系统时,学生可以作为一个对象,学生的属性包括姓名、年龄、班级等,学生的方法可以包括报名、考试等操作。面向对象方法有利于代码的复用和系统的扩展。通过定义类和对象,可以方便地构建复杂的系统。
(三)信息系统开发工具
- 编程语言
- 常见的编程语言有Java、Python、C++等。Java是一种面向对象的编程语言,具有跨平台的特点,被广泛应用于企业级应用开发。例如,很多大型的电子商务网站的后端服务就是用Java开发的。Python语言语法简洁,开发效率高,适合进行数据分析、人工智能等领域的开发。例如,在开发一个数据挖掘系统时,可以使用Python语言来实现数据处理和分析算法。
- 数据库管理系统
- 数据库是信息系统的核心组成部分。常见的数据库管理系统有MySQL、Oracle、SQL Server等。MySQL是一种开源的数据库管理系统,具有成本低、性能稳定的特点,被广泛应用于中小企业和互联网应用。Oracle数据库功能强大,适合处理大规模的数据,常用于金融、电信等行业的核心业务系统。
- 开发框架
- 开发框架可以提高开发效率。例如,Spring框架是Java开发中常用的框架,它提供了依赖注入、事务管理等功能,使得开发人员可以更加专注于业务逻辑的实现。Django是Python开发的一个高级Web框架,它内置了许多功能,如用户认证、模板引擎等,能够快速开发出功能完善的Web应用。
(四)信息系统开发的流程
- 需求分析
- 这是开发过程的第一步,也是最关键的一步。需求分析的目的是明确用户对系统的期望和要求。开发人员要与用户进行充分的沟通,通过问卷调查、访谈等方式收集需求。例如,在开发一个企业资源管理系统时,要了解企业各部门的业务流程,明确系统需要支持哪些业务功能。
- 设计阶段
- 根据需求分析的结果,进行系统设计。设计包括总体架构设计和详细设计。总体架构设计确定系统的整体结构,如系统的分层结构(如表现层、业务逻辑层、数据访问层)。详细设计则包括模块设计、数据库设计等。例如,在设计一个在线教育系统时,要确定系统的模块划分,如课程管理模块、用户管理模块、学习进度跟踪模块等。
- 编码阶段
- 开发人员根据设计文档进行编程。编码阶段要遵循良好的编程规范,确保代码的可读性和可维护性。例如,在编写代码时,要合理命名变量和函数,添加注释,方便其他开发人员理解和维护代码。
- 测试阶段
- 测试是确保系统质量的重要环节。测试包括单元测试、集成测试和系统测试。单元测试是对系统中的每个模块进行单独测试,检查模块的功能是否正常。集成测试是在将多个模块组合在一起后进行测试,检查模块之间的接口是否正确。系统测试则是对整个系统进行测试,包括功能测试、性能测试、安全性测试等。例如,在测试一个支付系统时,要测试支付功能是否正常,支付过程是否安全,系统在高并发情况下的性能如何等。
- 上线和维护阶段
- 系统测试通过后,就可以将系统上线运行。上线后,要对系统进行维护,及时解决用户在使用过程中遇到的问题。同时,根据用户反馈和业务发展需求,对系统进行升级和优化。例如,一个社交软件上线后,可能会根据用户反馈增加新的聊天功能,或者优化图片分享功能。
以下是关于信息化及信息系统开发的基本知识介绍,涵盖核心概念、开发流程、关键技术等内容:
- 系统测试通过后,就可以将系统上线运行。上线后,要对系统进行维护,及时解决用户在使用过程中遇到的问题。同时,根据用户反馈和业务发展需求,对系统进行升级和优化。例如,一个社交软件上线后,可能会根据用户反馈增加新的聊天功能,或者优化图片分享功能。
一、信息化基础概念
1. 信息化的定义
信息化是指利用计算机、通信网络、物联网等信息技术,对数据和信息进行采集、处理、存储、传输和应用,以提高社会生产效率、优化资源配置、推动社会发展的过程。
核心目标:通过信息技术实现信息资源的深度开发和广泛利用,提升各领域(如企业、政府、教育等)的智能化、自动化水平。
2. 信息化的核心要素
- 信息技术:包括计算机技术、网络技术、数据库技术、云计算、大数据、人工智能(AI)、物联网(IoT)等。
- 信息资源:数据、信息及其处理后的知识,是信息化的核心资产。
- 信息系统:用于支持信息化的软件系统,如管理信息系统(MIS)、企业资源计划(ERP)、客户关系管理(CRM)等。
- 信息化人才:掌握信息技术和行业知识的复合型人才。
- 政策与标准:保障信息化有序发展的法规、规范和技术标准。
3. 信息化的应用领域
- 企业信息化:如数字化营销、智能制造、供应链管理信息化。
- 政务信息化:如电子政务、智慧城市、数据治理。
- 教育信息化:如在线教育平台、智慧教室、教育资源共享。
- 医疗信息化:如电子病历(EMR)、医疗大数据、远程诊疗系统。
- 金融信息化:如移动支付、区块链金融、智能风控系统。
二、信息系统开发概述
1. 信息系统的定义
信息系统是由计算机硬件、软件、数据、流程和人员组成的有机整体,用于收集、处理、存储、传播信息,以支持组织的决策、管理和业务运作。
典型分类:
- 事务处理系统(TPS):如银行交易系统、超市收银系统。
- 管理信息系统(MIS):如企业报表系统、库存管理系统。
- 决策支持系统(DSS):如数据分析平台、商业智能(BI)系统。
- 人工智能系统:如智能客服、图像识别系统。
2. 信息系统开发的目标
- 解决业务问题:如提高效率、降低成本、优化流程。
- 支持决策:通过数据可视化和分析辅助管理层决策。
- 提升竞争力:通过数字化手段实现业务创新(如电商平台、O2O模式)。
3. 信息系统开发的特点
- 系统性:需综合考虑业务流程、技术架构和用户需求。
- 复杂性:涉及多学科知识(如软件工程、数据库、网络技术)。
- 动态性:需适应业务需求和技术的变化(如需求迭代、技术升级)。
- 用户参与性:用户需求是开发的核心,需持续沟通和反馈。
三、信息系统开发流程
信息系统开发通常遵循软件工程的方法论,以下是瀑布模型的典型流程(其他模型如敏捷开发、迭代开发可灵活调整):
1. 需求分析
- 任务:与用户沟通,明确系统目标、功能需求、性能需求(如响应速度、安全性)和约束条件(如预算、时间)。
- 工具:需求规格说明书(SRS)、用例图(UML)、原型设计(如Axure)。
- 关键问题:避免需求模糊(如“系统要好用”需细化为具体操作流程)。
2. 系统设计
- 任务:将需求转化为技术实现方案,分为概要设计和详细设计。
- 概要设计:确定系统架构(如C/S或B/S架构)、数据库逻辑模型(ER图)、模块划分(如用户管理、订单管理)。
- 详细设计:细化模块功能、算法逻辑、界面设计(如UI原型)、数据库物理模型(表结构、索引设计)。
- 工具:Visio(流程图)、PowerDesigner(数据库设计)、UML类图/时序图。
3. 系统开发(编码实现)
- 任务:根据设计文档编写代码,实现功能模块。
- 技术栈选择:
- 前端:HTML/CSS/JavaScript、框架(React/Vue/Angular)。
- 后端:Java/Python/Node.js等语言,框架(Spring Boot/Django/Express)。
- 数据库:关系型数据库(MySQL/PostgreSQL)、非关系型数据库(MongoDB)。
- 部署:云服务器(AWS/阿里云)、容器化(Docker/Kubernetes)。
- 关键原则:代码可读性、可维护性、遵循设计模式(如单例模式、工厂模式)。
4. 系统测试
- 任务:验证系统是否满足需求,发现并修复缺陷。
- 测试类型:
- 单元测试:测试单个函数或模块(如Java的JUnit)。
- 集成测试:测试模块间的交互(如接口联调)。
- 系统测试:测试整个系统的功能、性能、安全性(如压力测试、漏洞扫描)。
- 用户验收测试(UAT):用户参与测试,确认系统符合预期。
- 工具:Jira(缺陷管理)、Postman(接口测试)、LoadRunner(性能测试)。
5. 部署与维护
- 部署:将系统发布到生产环境,可能涉及数据迁移、服务器配置、权限设置。
- 维护:
- 纠错性维护:修复运行中发现的bug。
- 适应性维护:适应环境变化(如操作系统升级、政策变更)。
- 完善性维护:新增功能或优化用户体验(如界面改版)。
- 预防性维护:提前优化系统架构,应对未来需求。
四、信息系统开发关键技术
1. 软件开发技术
- 编程语言:Java(企业级系统)、Python(快速开发)、C#(.NET平台)、Go(高并发系统)等。
- 框架与工具:Spring(JavaEE框架)、Django(Python全栈框架)、React Native(跨平台移动开发)。
- DevOps:开发(Development)与运维(Operations)结合,实现自动化部署和监控(如Jenkins、GitLab CI/CD)。
2. 数据库技术
- 关系型数据库:适合结构化数据(如用户订单),支持事务和复杂查询。
- 非关系型数据库(NoSQL):适合非结构化数据(如日志、图片),支持高并发和横向扩展(如Redis缓存、MongoDB文档存储)。
- 数据仓库与大数据:Hadoop/Spark处理海量数据,支持数据分析和机器学习。
3. 网络与安全技术
- 网络架构:分布式架构、微服务架构(将系统拆分为独立服务,如电商中的用户服务、商品服务)。
- 安全性:数据加密(如HTTPS、AES)、身份认证(OAuth/JWT)、防火墙、入侵检测系统(IDS)。
4. 新兴技术应用
- 云计算:通过云服务(IaaS/PaaS/SaaS)降低硬件成本,提升扩展性(如AWS EC2、阿里云ECS)。
- 人工智能:机器学习(ML)用于数据分析,自然语言处理(NLP)用于智能交互。
- 物联网:通过传感器和设备联网实现数据采集(如智能工厂设备监控)。
五、信息化与系统开发的挑战
- 需求变更管理:用户需求可能随业务调整而变化,需通过敏捷开发等方法灵活应对。
- 技术选型风险:选择过时或小众技术可能导致维护困难,需评估技术成熟度和社区支持。
- 数据安全与合规:需遵守隐私法规(如GDPR、中国《数据安全法》),防止数据泄露。
- 跨部门协作:开发团队需与业务部门、运维团队密切配合,避免“技术与业务脱节”。
- 系统性能优化:处理高并发、大数据量时需优化算法和架构(如缓存机制、分布式存储)。
六、学习建议
- 理论基础:学习《软件工程》《数据库系统概论》《计算机网络》等经典教材。
- 实践项目:通过开源项目(如GitHub)或实训平台(如实验楼)动手开发,积累经验。
- 关注技术趋势:跟踪云计算、AI、低代码开发(如Power Apps)等前沿领域。
- 考取认证:如软件设计师(中级)、系统架构师(高级)、PMP(项目管理)等。
通过以上知识,可初步建立对信息化和信息系统开发的认知,后续可结合具体领域(如企业管理、金融科技)深入学习。
以下是Grails 1.3中命名查询的用法示例:
1. 定义命名查询(Domain类)
class Book {
String title
String author
Integer year
Boolean published = false
static constraints = {
title blank: false
author nullable: true
}
// 命名查询定义
static namedQueries = {
// 查询已出版的书籍
publishedBooks {
eq('published', true)
}
// 按作者和年份查询
byAuthorAndYear { String authorName, Integer yearPublished ->
eq('author', authorName)
eq('year', yearPublished)
}
// 带排序的查询(按年份降序)
recentBooks { max ->
order('year', 'desc')
maxResults(max)
}
// 支持子查询
booksByPublisher { publisherName ->
publisher {
eq('name', publisherName)
}
}
}
}
2. 在Service中使用命名查询
class BookService {
def listPublishedBooks() {
// 直接调用命名查询
return Book.publishedBooks().list()
}
def findBooksByAuthorAndYear(String author, int year) {
// 带参数的命名查询
return Book.byAuthorAndYear(author, year).list()
}
def getRecentBooks(int count) {
// 带动态参数的命名查询
return Book.recentBooks(count).list()
}
}
3. 在Controller中调用
class BookController {
def bookService
def listPublished = {
def books = bookService.listPublishedBooks()
render(view: "list", model: [books: books])
}
def findByAuthor = {
def books = Book.byAuthorAndYear(params.author, params.year?.toInteger()).list()
render(view: "list", model: [books: books])
}
}
4. 命名查询的高级用法
参数化条件
static namedQueries = {
flexibleSearch { String titlePattern, Integer minYear ->
if(titlePattern) {
ilike('title', "%${titlePattern}%")
}
if(minYear) {
ge('year', minYear)
}
}
}
// 调用示例
def results = Book.flexibleSearch("Grails", 2010).list()
组合多个命名查询
def recentPublishedBooks = Book.publishedBooks().recentBooks(5).list()
5. 关联实体的命名查询
class Publisher {
String name
static hasMany = [books: Book]
}
class Book {
static belongsTo = [publisher: Publisher]
static namedQueries = {
// 查询特定出版社的书籍
fromPublisher { publisherName ->
publisher {
eq('name', publisherName)
}
}
}
}
// 使用示例
def oreillyBooks = Book.fromPublisher("O'Reilly").list()
关键特性说明:
- 可复用性:命名查询定义一次后可在多处调用
- 参数化:支持带参数的动态查询
- 链式调用:多个命名查询可链式组合使用
- GORM集成:与其他GORM方法无缝配合(如list()、count()等)
- 延迟执行:命名查询返回的是查询对象,调用list()/get()等方法时才执行SQL
与1.3版本相关的注意事项:
- Grails 1.3使用Hibernate 3.3,命名查询语法需兼容该版本
- 不支持Grails 2.0+引入的静态查询方法(如
static finders
) - 查询缓存需通过
cache(true)
显式启用 - 建议在
BootStrap.groovy
中预加载命名查询以提高性能
Grails 1.3 是一个基于 Groovy 的 Web 应用开发框架,它在 1.2 版本的基础上进行了改进和优化,引入了许多新特性和核心功能。以下是 Grails 1.3 的一些核心功能:
1. GORM(Grails Object-Relational Mapping)改进
- 新增
beforeValidate
方法:在验证之前可以对对象进行处理,例如清理数据。 - 查询支持排序和缓存:支持在查询时指定排序方式和是否使用缓存。
- 脏数据检查:可以检查对象是否被修改,以及单独字段是否被修改。
- Hibernate 属性支持:允许设置 Hibernate 的
insert="false"
和update="false"
属性。
2. 框架和配置
- 动态重新加载 GSP:可以在开发过程中动态重新加载预编译的 GSP 页面。
- 全局布局配置:可以在
Config.groovy
中设置全局的布局。 - 资源文件动态加载:可以在
resource.groovy
中动态访问应用程序实例。 - Tomcat JVM 参数配置:可以在
BuildConfig.groovy
中设置 Tomcat 的 JVM 参数。
3. 视图和 Web 标签
link
标签增强:支持attrs
属性,可以更灵活地生成 HTML 标签。- 新增
unless
标签:与if
标签类似,但逻辑相反。 - 新增
join
标签:用于将数组元素连接成字符串。
4. Web Flow 支持
Grails 1.3 支持基于 Spring Web Flow 的多步流程管理,适合处理复杂的多页面交互,例如购物车、预订流程等。
5. 依赖注入和服务
- 自动依赖注入:支持通过约定自动注入服务到控制器、标签库等。
- 服务注入到领域类:可以在领域类中注入服务,从而实现更丰富的领域模型。
6. 测试支持
Grails 提供了强大的测试支持,包括单元测试和集成测试。create-*
命令会自动生成测试类,方便开发者快速编写测试。
7. 其他改进
- 修复大量 Bug:包括对 HSQLDB、GORM 约束、查询执行、Maven 插件安装等问题的修复。
- 性能优化:通过优化 Hibernate 会话管理和减少不必要的日志记录,提升了性能。
总体而言,Grails 1.3 在 GORM、Web 开发、配置灵活性和性能方面都有显著提升,为开发者提供了更强大的工具来构建高效、可维护的 Web 应用。
“More Grails 1.3 features”可直译为“更多Grails 1.3特性”。
Grails是基于Java和Groovy构建的动态Web应用程序框架。“More Grails 1.3 features”很可能是一篇介绍Grails 1.3版本更多特性的文章标题或主题,旨在讲述该版本除了一些主要特性之外的其他功能特点。
根据相关资料,Grails 1.3版本有诸多新特性。例如,引入了对Groovy 1.7的支持,包括匿名和嵌套类支持等新功能;开始使用JUnit 4来运行测试;完全支持将插件发布到Maven兼容的存储库以及从其中读取插件,还可使用Ivy DS声明插件依赖性;GORM新增了用于检查对象是否已修改的新方法等。此外,还有名为“命名查询(named queries)”的功能,它允许开发者在域类中定义可复用的查询,方便在控制器动作或服务方法中调用,提高代码的可维护性和复用性。
Last week, I described how Grails now treats plugins like normal dependencies that can be pulled from Maven-compatible repositories. Although this was the big new feature for 1.3, it wasn’t the only one. In this post, I’ll look at some of the others, starting with a feature that I only recently found out about.
Named queries
GORM provides three distinct ways of performing database queries:
dynamic finders, e.g. Book.findByTitleAndAuthorLike(…);
criteria queries, which use a nice DSL; and
HQL, Hibernate’s SQL-like query language.
These three features provide a potent mix of ease-of-use and power, providing you with the flexibility you need. And yet there’s something missing.
Develop a non-trivial Grails application and you will soon realise that you often use the same queries again and again. What should you do? The copy-and-paste technique is simple but leaves you with major maintenance issues. You could write service methods for each of your common queries, but then you end up with quite fine-grained services and a pretty dumb domain model. The ideal place for these queries is on the domain classes themselves.
That’s where named queries come in - a feature that slipped under the radar and into Grails 1.2.
An example
Let’s consider a simple domain model related to reports:
[caption id=“attachment_4791” align=“alignnone” width=“398”]Domain model for reports[/caption]
The basic idea is that a report can be about one or more servers and it may be generated one or more times a month. So dow stands for “day of week” and wom stands for “week of month”. Each server has an associated location, which is just the name of a city in this much-reduced model.
Now consider what sort of information an application might want to extract from this model: perhaps all reports generated in the first week of the month, or all reports about a particular server. We could add static methods to the Report class to provide such queries, but named queries give us some additional benefits that you’ll see later.
Creating a named query is straightforward, as you would expect with Grails. Simply add a static namedQueries property to the relevant domain class and assign a closure to it:
class Report {
String name
static hasMany = [frequencies: Frequency, servers: Server]
static namedQueries = {
inFirstWeek {
frequencies {
eq("wom", 1)
}
}
inWeek { wom ->
frequencies {
eq("wom", wom)
}
}
dilbertsReports {
servers {
eq("mgrEmail", "dilbert@nowhere.org")
}
}
inCity { city ->
servers {
location {
eq("city", city)
}
}
}
}
The code above sets up four queries: inFirstWeek, inWeek, dilbertsReports, and inCity. You can then use them in the same places that you can use dynamic finders, for example in controller actions or service methods. If you want to retrieve all reports that are generated in the first week of the month, call the relevant named query like so:
Report.inFirstWeek.list()
If you want all reports generated in one of the other weeks of the month, then use inWeek instead:
Report.inWeek(2).list()
See how you can pass arguments to the named queries? Just make sure that your named query closure declares the appropriate number of arguments.
Hopefully you can see how easy it is to both declare and use named queries, but before I move on, a few points deserve clarification.
First, you must write the queries in Grails’ criteria DSL. If you’ve been putting off learning about the criteria DSL, you now have a good reason to cease procrastinating!
Second, you invoke the DSL as a static property (if you aren’t passing any arguments to it) or method, followed by a standard GORM retrieval method, such as list(), get(), or a dynamic finder. That means you can add extra filtering to your named queries. It’s also worth pointing out that get() will only return a domain instance if the result of the named query contains the required entity. Otherwise, get() simply returns null.
In other words, let’s say the inFirstWeek query returns the domain instances with IDs of 1, 3, and 6. Then
Report.inFirstWeek.get(3)
will return the domain instance with ID of 3, whereas
Report.inFirstWeek.get(2)
will return null, even if Report.get(2) returns a real domain instance. So the named query acts like a filter.
So far, so good. The way that the named queries combine with get(), list(), and dynamic finders may be enough of a reason to use them right away. But Grails 1.3 includes another trick up its sleeve.
Chaining queries
How do arbitrary combinations of named queries sound? Well, by chaining named queries, you have just that. For example, if I want all of Dilbert’s reports that are generated in the first week of the month, I can call
Report.dilbertsReports.inFirstWeek.list()
Alternatively, if I want all first week reports about servers in London, I can use
Report.inFirstWeek.inCity(“London”).list()
In fact, you can chain as many named queries as you like, as long as they all return the same type of domain class.
Named queries provide a powerful technique for query reuse that is both simple to implement and to use. You can now have a very rich domain model with client code that is easy to read and understand. How good is that?
Now I’d like to quickly look at some other Grails 1.3 features.
Best of the rest
Smaller, but still useful, features made it into the Grails 1.3 release. Foremost of these was the upgrade to Groovy 1.7 (Grails 1.2 and previous are based on Groovy 1.6).
Groovy 1.7
Many fixes and enhancements went into the Groovy 1.7 release, but perhaps two are the most significant for Grails developers:
Anonymous and inner classes now supported - so integration with frameworks like Wicket should be much easier.
Power asserts - you can now use the Groovy assert keyword instead of the JUnit/TestNG alternatives to get impressive diagnostic information on why an assertion failed. My favourite new feature!
Dirty checking
No, this has nothing to do with household chores! As many of you are aware, Hibernate will automatically check whether a domain instance has been modified and persist the changes at the end of the session. GORM now allows you access to this feature via the isDirty() method:
def book = Book.get(10)
assert !book.dirty
book.title = “Unknown”
assert book.dirty
assert book.isDirty(“title”)
assert !book.isDirty(“author”)
See how you can also check whether individual fields have been modified?
Global layouts
As you probably know, Grails allows you to apply layouts to views either explicitly, via a tag, or by convention. What it didn’t allow you to do is specify a default layout for views as a fallback option. That deficiency has now been rectified and you can specify the default layout either via a setting in Config.groovy:
grails.sitemesh.default.layout = ‘defaultLayout’
or by creating the file grails-app/views/layouts/application.gsp. The first approach would pick up the layout from grails-app/views/layouts/defaultLayout.gsp.
JUnit 4
For all those testing fans out there, Grails finally comes with JUnit 4 by default, so you can now annotate your test cases to your heart’s content.
With that, I’ll wrap up this instalment of Grails 1.3 features. I hope you can make good use of the named queries! Next time, I’ll look at in-place plugins.
我描述了Grails现在如何将插件视为可以从Maven兼容存储库中提取的普通依赖项。虽然这是1.3的新特性,但它并不是唯一的。在这篇文章中,我将从我最近才发现的一个特性开始,看看其他的一些特性。
命名查询
GORM提供了三种不同的执行数据库查询的方法:
动态查找程序,例如Book.findByTitleAndAuthorLike(…);
标准查询,使用一个好的DSL;以及
HQL,Hibernate的类似SQL的查询语言。
这三个特性提供了易用性和强大功能的强大组合,为您提供了所需的灵活性。但还是少了点什么。
开发一个非常重要的Grails应用程序,您很快就会意识到,您经常一次又一次地使用相同的查询。你该怎么办?复制粘贴技术很简单,但会给您带来重大的维护问题。您可以为每个常见查询编写服务方法,但最终会得到相当细粒度的服务和相当愚蠢的域模型。这些查询的理想位置是域类本身。