一:准备工作
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,有困难大家一起讨论~~~