一:准备工作
1.下载安装MySql,确保安装成功。
2.下载mave、springside并配置,参考:https://github.com/springside/springside4/wiki/QuickStart
3.Eclipse配置m2eclipse.参考上篇博客:http://my.oschina.net/robinjiang/blog/83735
4.成功运行quickstart,运行界面如下:
二: 配置Mysql
1.官方参考资料:https://github.com/springside/springside4/wiki/DataBase
2.修改pom.xml,注释掉h2相关配置
<!-- 项目属性,修改为mysql --> <!-- <jdbc.driver.groupId>com.h2database</jdbc.driver.groupId> <jdbc.driver.artifactId>h2</jdbc.driver.artifactId> <jdbc.driver.version>${h2.version}</jdbc.driver.version> --> <jdbc.driver.groupId>mysql</jdbc.driver.groupId> <jdbc.driver.artifactId>mysql-connector-java</jdbc.driver.artifactId> <jdbc.driver.version>5.0.8</jdbc.driver.version>
<!-- 注释掉 <dependency> <groupId>com.h2database</groupId> <artifactId>h2</artifactId> <version>${h2.version}</version> <scope>test</scope> </dependency> -->
<!-- 修改刷新开发环境数据库,将sql脚本定义至mysql的脚本 --> <sql driver="${jdbc.driver}" url="${jdbc.url}" userid="${jdbc.username}" password="${jdbc.password}" onerror="continue"> <classpath refid="maven.test.classpath" /> <transaction src="src/main/resources/sql/mysql/schema.sql"/> <transaction src="src/test/resources/data/import-data.sql"/> </sql>
3.修改application.properties
#mysql database setting jdbc.driver=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql://localhost:3306/springdb?useUnicode=true&characterEncoding=utf-8 jdbc.username=root jdbc.password=1234 #dbcp settings dbcp.maxIdle=5 dbcp.maxActive=40
4.修改applicationContext.xml相应部分
如果在functional测试期间也需要使用mysql,更改application.functional.properties中的配置,并且修改applicatonContext.xml的functional profile中的sql脚本目录。
5.在mysql下新建数据库(例如:springdb),然后运行springside下的mysql脚本
6.运行springside项目bin下的refresh-db.bat,刷新数据。会看到表中多了数据
三:CRUD示例
官方资料:https://github.com/springside/springside4/wiki/Tutorial。但是我按照官方资料运行有点错误,所以自己总结下。
1.数据库设计:
在src/resouces/sql/mysql/schema.sql 中手工编写创建表的sql。 建好之后最好运行springside项目bin下的refresh-db.bat,刷新数据。
create table acct_user ( id bigint auto_increment, email varchar(255), login_name varchar(255) not null unique, name varchar(255), password varchar(255), primary key (id) ) engine=InnoDB;
2.Entity
2.1 手工编写Entity,利用默认大于配置原理,写尽量少的注释, 一般只有带前缀的表名,Cache和关联属性需要注释。
package org.springside.examples.quickstart.entity; import javax.persistence.Entity; import javax.persistence.Table; import org.hibernate.validator.constraints.NotBlank; //JPA标识 @Entity @Table(name="ACCT_USER") public class UserDemo extends IdEntity { private String loginName; private String password; private String name; private String email; @NotBlank public String getLoginName() { return loginName; } public void setLoginName(String loginName) { this.loginName = loginName; } 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 getEmail() { return email; } public void setEmail(String email) { this.email = email; } }
2.2 执行test中的JpaMapptingTest.java校验ORM配置正确。
2.3 Spring的LocalContainerEntityManagerFactoryBean能自动扫描packagesToScan中的@Entity类,无需逐一配置。
3.DAO
3.1写一个简单的DAO接口,日后再根据需要添加方法定义。
package org.springside.examples.quickstart.repository; import org.springframework.data.repository.PagingAndSortingRepository; import org.springside.examples.quickstart.entity.UserDemo; public interface UserDemoDao extends PagingAndSortingRepository<UserDemo, Long> { }
3.3 如果有复杂的操作或ORM关系可添加单元测试,否则可忽略。
4.Service
4.1 按业务划分新建或使用已有Service(与DAO不应是一一对应关系),根据需求添加方法定义。 注意事务定义。
package org.springside.examples.quickstart.service.userdemo; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.Sort; import org.springframework.data.domain.Sort.Direction; import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; import org.springside.examples.quickstart.entity.UserDemo; import org.springside.examples.quickstart.repository.UserDemoDao; @Component @Transactional(readOnly = true) public class UserDemoService { private UserDemoDao userDemoDao; @Autowired public void setUserDemoDao(UserDemoDao userDemoDao) { this.userDemoDao = userDemoDao; } public UserDemo findUserDemobyName(Long id) { return userDemoDao.findOne(id); } @Transactional(readOnly = false) public void deleteUserDemo(Long id) { userDemoDao.delete(id); } @Transactional(readOnly = false) public void saveUserDemo(UserDemo userDemo) { userDemoDao.save(userDemo); } public List<UserDemo> findAllUserDemo() { return (List<UserDemo>) userDemoDao.findAll(((new Sort(Direction.ASC, "id")))); } }
4.2 Spring能根据applicationContext.xml中的<context:component-scan...>自动扫描@Service或@Component, 无需配置。
4.3 对有业务逻辑的方法要编写单元测试,并用Mock框架模拟dao层。
5.Web Controller
5.1 我这里写了两个controller 一个负责增、查、删
package org.springside.examples.quickstart.web.userdemo; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.servlet.mvc.support.RedirectAttributes; import org.springside.examples.quickstart.entity.UserDemo; import org.springside.examples.quickstart.service.userdemo.UserDemoService; /** * List page: * @author Robin * */ @Controller @RequestMapping(value = "/userDemo") public class UserDemoController { @Autowired private UserDemoService userDemoService; @RequestMapping(value ={"list",""}) public String list(Model model) { List<UserDemo> userDemos = userDemoService.findAllUserDemo(); model.addAttribute("userDemos", userDemos); return "userDemo/userDemoList"; } @RequestMapping(value = "create", method = RequestMethod.GET) public String createForm(Model model) { model.addAttribute("userDemo", new UserDemo()); //设置跳转的action 但是未成功。采用写死的方法 //model.addAttribute("action", "create"); return "userDemo/userDemoForm"; } @RequestMapping(value = "save", method = RequestMethod.POST) public String create(UserDemo newUserDemo, RedirectAttributes redirectAttributes) { userDemoService.saveUserDemo(newUserDemo); redirectAttributes.addFlashAttribute("message", "创建"+newUserDemo.getLoginName()+"成功"); return "redirect:/userDemo/"; } @RequestMapping(value = "delete/{id}") public String delete(@PathVariable("id") Long id, RedirectAttributes redirectAttributes) { userDemoService.deleteUserDemo(id); redirectAttributes.addFlashAttribute("message", "删除任务成功"); return "redirect:/userDemo/"; } }
5.2 另外一个负责修改
package org.springside.examples.quickstart.web.userdemo; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.servlet.mvc.support.RedirectAttributes; import org.springside.examples.quickstart.entity.UserDemo; import org.springside.examples.quickstart.service.userdemo.UserDemoService; @Controller @RequestMapping(value = "/userDemo") public class UserDemoUpdateController { private UserDemoService userDemoService; @Autowired public void setUserDemoService(UserDemoService userDemoService) { this.userDemoService = userDemoService; } @RequestMapping(value = "update/{id}") public String updateForm(Model model) { return "userDemo/userDemoForm"; } @RequestMapping(value = "save/{id}") public String update(@ModelAttribute("userDemo") UserDemo userDemo, RedirectAttributes redirectAttributes) { userDemoService.saveUserDemo(userDemo); redirectAttributes.addFlashAttribute("message", "更新" + userDemo.getLoginName() + "成功"); return "redirect:/userDemo/"; } /** * 使用@ModelAttribute, 实现Struts2 * Preparable二次部分绑定的效果,先根据form的id从数据库查出Task对象,再把Form提交的内容绑定到该对象上。 * 因为仅update()方法的form中有id属性,因此本方法在该方法中执行. */ @ModelAttribute("userDemo") public UserDemo getUserDemoId(@PathVariable("id") Long id) { return userDemoService.findUserDemobyName(id); } }5.3 Spring能根据spring-mvc.xml中的<context:component-scan> 自动扫描@Controller, 无需配置。
5.4 如果有participation update的情况,即Form表单中的变量没有包含Entity中的所有属性,一个方法是另外编写一个DTO,一个方法是参照quickstart中基于@ModelAttribute的二次绑定的做法。
6.JSP
总共两个jsp页面,在WEB-INF的views文件夹下新建userDemo,在其中创建两个jsp文件:userDemoForm.jsp,userDemoList.jsp
6.1 userDemoForm.jsp
<%@ page contentType="text/html;charset=UTF-8" %> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <c:set var="ctx" value="${pageContext.request.contextPath}"/> <html> <head> <title>UserDemo管理</title> <script> $(document).ready(function() { //聚焦第一个输入框 $("#userDemo_loginName").focus(); //为inputForm注册validate函数 $("#inputForm").validate(); }); </script> </head> <body> <form id="inputForm" action="${ctx}/userDemo/save/${userDemo.id}" method="POST" class="form-horizontal"> <input type="hidden" name="id" value="${userDemo.id}"/> <fieldset> <legend><small>管理UserDemo任务</small></legend> <div class="control-group"> <label for="userDemo_loginName" class="control-label">LoginName:</label> <div class="controls"> <input type="text" id="userDemo_loginName" name="loginName" value="${userDemo.loginName}" class="input-large required" minlength="3"/> </div> </div> <div class="control-group"> <label for="userDemo_password" class="control-label">Password:</label> <div class="controls"> <textarea id="userDemo_password" name="password" class="input-large">${userDemo.password}</textarea> </div> </div> <div class="control-group"> <label for="userDemo_name" class="control-label">Name:</label> <div class="controls"> <textarea id="userDemo_name" name="name" class="input-large">${userDemo.name}</textarea> </div> </div> <div class="control-group"> <label for="userDemo_email" class="control-label">Email:</label> <div class="controls"> <textarea id="userDemo_email" name="email" class="input-large">${userDemo.email}</textarea> </div> </div> <div class="form-actions"> <input id="submit_btn" class="btn btn-primary" type="submit" value="提交"/> <input id="cancel_btn" class="btn" type="button" value="返回" onclick="history.back()"/> </div> </fieldset> </form> </body> </html>
6.2 userDemoList.jsp
<%@ page contentType="text/html;charset=UTF-8" %> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <%@ taglib prefix="tags" tagdir="/WEB-INF/tags" %> <c:set var="ctx" value="${pageContext.request.contextPath}"/> <html> <head> <title>UserDemo管理</title> </head> <body> <c:if test="${not empty message}"> <div id="message" class="alert alert-success"><button data-dismiss="alert" class="close">×</button>${message}</div> </c:if> <!-- <div class="row"> <div class="span4 offset7"> <form class="form-search" action="#"> <label>查询条件(id):</label> <input type="text" name="search_LIKE_id" class="input-medium" value="${param.search_LIKE_id}"> <button type="submit" class="btn">Search</button> </form> </div> <tags:sort/> </div> --> <table id="contentTable" class="table table-striped table-bordered table-condensed"> <thead><tr><th>登录名</th><th>密码</th><th>姓名</th><th>邮箱</th><th>操作</th></tr></thead> <tbody> <c:forEach items="${userDemos}" var="userDemo"> <tr> <td><a href="${ctx}/userDemo/update/${userDemo.id}">${userDemo.loginName}</a></td> <td>${userDemo.password}</td> <td>${userDemo.name}</td> <td>${userDemo.email}</td> <td><a href="${ctx}/userDemo/delete/${userDemo.id}">删除</a></td> </tr> </c:forEach> </tbody> </table> <div><a class="btn" href="${ctx}/userDemo/create">创建用户</a></div> </body> </html>
6.3 为方便查看userdemo修改header.jsp ,添加一行代码:<li><a href="${ctx}/userDemo">userDemo</a></li>
7.最好重启下eclipse。运行结果如下:
四:遇到的问题
1.修改配置文件后,必须要重启eclipse,否则不能正确读取,不知道是什么原因。
2.Invocation of init method failed错误。
解决办法:@RequestMapping(value = "save") 多个requestmapping 的value值相同,设置为不同的值。
3.开发过程中可能会遇到运行refresh-db.bat出错的问题,可能是由于没有mysql-connector jar包引起的,此外还要注意mysql-connector 的版本问题,在配置文件中要注意。
说明:我也是刚开始研究接触springside,有困难大家一起讨论~~~