目錄
建立項目
以在線商城爲例,演示idea如何搭建ssm開發環境。如果覺得maven下載速度過慢,可以打開c盤的user目錄中的.m2文件夾下的setting.xml文件夾目錄,修改爲阿里源,然後重啓。這樣還是不行建議翻牆試試。
<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0
https://maven.apache.org/xsd/settings-1.0.0.xsd">
<mirrors>
<mirror>
<id>alimaven</id>
<name>aliyun maven</name>
<url>http://maven.aliyun.com/nexus/content/groups/public/</url>
<mirrorOf>central</mirrorOf>
</mirror>
</mirrors>
</settings>
創建各層的package
在這裏請選擇spring
和springmvc
,然後一路next就能創建成功。之後請在src
的包下創建四個模塊
- controller
- service
- dao
- pojo
創建resource目錄
右鍵最上層的文件夾創建一個與src
、web
相同級別的resource
目錄。將此目錄設置成resource root
,右鍵resource
選擇 Make Directory as ->resource root
。爲什麼需要這麼做?因爲可以在許多的地方使用classpath:
來引用這個目錄,否則使用一般文件目錄可能就無法生效,這很重要,後面會有講到在哪裏使用。
在springboot
中classpath
默認是resource
目錄。在springmvc
中默認是src
目錄。
新建實體對象
public class Book {
private int id;
private String name;
private String Author;
private double price;
private String image;
private String description;
private int category_id;
//省略setter、getter
}
/*-----------分割線,請在兩個不同class文件中建立這兩個對象---------------*/
public class Category {
private int id;
private String name;
private String description;
}
sql 代碼
CREATE TABLE `book` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` char(50) DEFAULT NULL,
`author` char(10) DEFAULT NULL,
`price` decimal(10,2) DEFAULT NULL,
`image` varchar(50) DEFAULT '/image/book.jpeg',
`description` varchar(1024) DEFAULT NULL,
`category_id` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `category_id` (`category_id`),
CONSTRAINT `book_ibfk_1` FOREIGN KEY (`category_id`) REFERENCES `category` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8mb4
CREATE TABLE `category` (
`id` int(11) NOT NULL,
`name` varchar(256) DEFAULT NULL,
`description` varchar(1024) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
完善目錄結構
- WEB-INF中
views
的文件夾,用來存放jsp文件 - 測試代碼目錄
test
- mybatis的xml文件目錄
mapper
- 靜態資源(css、js、image)
- 數據庫配置文件
db.properties
web.xml文件配置
這個文件是與Tomcat相關聯的,如果這個目錄出錯,服務器是無法啓動的,在這裏我們需要配置spring 和springmvc ,請在你爲web-app 中加入下面的內容,前面之所以需要建立resource文件夾是方便在這裏利用applicationContext.xml 和dispatch-servlet.xml 文件。 |
<!--配置spring-->
<context-param>
<param-name>contextConfigLocation</param-name>
<!--指定spring配置文件的位置-->
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!--配置springmvc-->
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!--加入初始化參數指定springmvc配置文件的路徑-->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:dispatcher-servlet.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<!--這裏需要修改一下-->
<url-pattern>/</url-pattern>
</servlet-mapping>
dispatch-servlet.xml文件配置
springmvc
管理的是controller
層,因此只需要掃描controller層的註解即可,其他層由spring的ioc容器管理。其次,要想在jsp中使用static
中的靜態資源需要爲其配置映射。請在你的beans
下添加下面內容
<!--mvc管理controller-->
<context:component-scan base-package="cn.edu.ncu.bookstore.controller"></context:component-scan>
<!--配套使用,啓動mvc註解-->
<mvc:annotation-driven />
<!--靜態資源映射-->
<mvc:resources mapping="/css/**" location="/WEB-INF/static/css" />
<mvc:resources mapping="/js/**" location="/WEB-INF/static/js" />
<mvc:resources mapping="/images/**" location="/WEB-INF/static/images" />
<!--配置邏輯視圖解析器-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="viewClass" value="org.springframework.web.servlet.view.JstlView"></property>
<property name="prefix" value="/WEB-INF/views/" />
<property name="suffix" value=".jsp" />
</bean>
applicationContext.xml文件配置
mybatis的配置和spring的配置都是在這個文件中進行,spring掃描包需要排除controller。這裏需要導入的包有:mybatis和mysql的jar。
<!--引入數據庫配置文件-->
<context:property-placeholder location="classpath:db.properties" />
<!--指定註解掃描路徑,排除controller-->
<context:component-scan base-package="cn.edu.ncu.bookstore">
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"></context:exclude-filter>
</context:component-scan>
<!--以下內容都是配置mybatis-->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${jdbc.driver}"></property>
<property name="url" value="${jdbc.url}"></property>
<property name="username" value="${jdbc.username}"></property>
<property name="password" value="${jdbc.password}"></property>
</bean>
<!--識別mapper文件-->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"></property>
<property name="mapperLocations" value="classpath:mapper/*.xml"></property>
</bean>
<!--<bean id="categoryDao" class="org.mybatis.spring.mapper.MapperFactoryBean">-->
<!--<property name="mapperInterface" value="cn.edu.ncu.bookstore.dao.CategoryDao"></property>-->
<!--<property name="sqlSessionFactory" ref="sqlSessionFactory"></property>-->
<!--</bean>-->
<!--導入所有的dao-->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="cn.edu.ncu.bookstore.dao"></property>
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"></property>
</bean>
db.properties
文件內容如下:
jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/test?characterEncoding=utf-8
jdbc.username=root
jdbc.password=123456
請根據自己的情況進行修改,另外mysql8版本的數據庫驅動名不再是com.mysql.jdbc.Driver
而是com.mysql.cj.jdbc.Driver
所以在導入mysql的驅動包時需要看清楚版本號
dao層開發
使用mybatis之後不需要在java中書寫sql語句,所有的數據庫操作都在xml文件中完成。使用repository和mapper其中之一就能完成bean的加入,看個人喜好
@Repository
@Mapper
public interface CategoryDao {
List<Category> findAll();
}
@Repository
@Mapper
public interface BookDao {
List<Book> findBookByCategoryId(@Param("id") int id);
}
然後在mapper層建立兩個mybatis-cogfig.xml配置文件
namespace指向你的具體dao接口,每個增刪改查操作的id都指向具體dao裏面的方法。
BookMapper.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.edu.ncu.bookstore.dao.BookDao">
<resultMap id="bookMap" type="cn.edu.ncu.bookstore.entity.Book">
<id property="id" column="id"></id>
<result property="name" column="name"></result>
<result property="author" column="author"></result>
<result property="price" column="price"></result>
<result property="description" column="description"></result>
<result property="category_id" column="category_id"></result>
</resultMap>
<select id="findBookByCategoryId" resultMap="bookMap">
select * from book where category_id = #{id}
</select>
</mapper>
CategoryMapper.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.edu.ncu.bookstore.dao.CategoryDao">
<resultMap id="categoryMap" type="cn.edu.ncu.bookstore.entity.Category">
<id property="id" column="id"></id>
<result property="name" column="name"></result>
<result property="description" column="description"></result>
</resultMap>
<select id="findAll" resultMap="categoryMap">
select * from category;
</select>
</mapper>
一般idea在新建文件時沒有mybatis-config.xml這個選項,但是我們可以加以一個模板,在setting->editor->file and code templates
中點擊‘+’,新建一個mybatis-config
,將extension
修改爲xml。將下面內容粘貼進去
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
關於方法傳參說明
注意到BookDao的findBookByCategoryId()
方法有一個@Param
註解,這個註解幾乎能解決所有的傳參問題。
@Param適用場景
- 當傳入參數有多個時,無法在xml文件中說明多個傳入參數的類型,如果用@Param註解就可以不用聲明參數的類型,可以直接用#{paramname}引用參數值
- 當參數是基本數據類型時可以使用這個註解
tips
:當傳入的參數是一個對象可以不用這個註解,就可以在引用參數時省略類名。例如,不使用該註解就能這麼寫#{name},如果使用註解就要這麼寫,#{user.name}。
還有很多書寫技巧,例如根據字段的等值匹配查詢數據可以不用創建多個select,一個select也能完成任務,例如:
<select id="findUserByColumn" returnType="User">
select * from user where ${column} = #{paramname};
</select>
這裏的column是你傳進來的String 類型的字段名稱,例如name,id等等,而paramname是查詢條件的值。
關於resultMap
resultMap是用來解決數據庫字段名與java對象名稱不匹配的情況,例如User對象有一個name屬性,而數據庫中是username,需要使用下面的語句進行映射。
<result properties="name" column="username">
如果有對象的屬性在數據庫中是主鍵則需要使用id
而不是result
,可以唯一標識一個對象mybatis更強大的關係映射請參考mybatis中文文檔,有一對多、一對一、多對多的關係,mybatis可以通過多表查詢結果自動實例化多個對象。這裏的關係也有許多細節需要注意,例如當可以保證查詢結果不爲空時使用連接查詢可以防止N+1的情況,如果多表查詢結果可能爲空,例如有一個User
和blog
表,在java
中的user
對象有一個List<Blog>
對象,但是在數據庫中blog
表中沒有該use
r發佈的blog
,在這種情況下使用連接查詢其結果就爲空,自然mybatis就無數據可以填充user對象,因此返回的user爲null
,但是我們需要的是user對象,List我們不關心,在這種情況下我們不得不N+1
,即查詢一個User獲得外鍵user_id後在blog表中判斷N遍將得到的結果去實例化List,N+1
極大的降低了效率。
service層開發
@Service
public class CategoryService {
@Autowired
private CategoryDao categoryDao;
public List<Category> findAll(){
return categoryDao.findAll();
}
}
@Service
public class BookService {
@Autowired
private BookDao bookDao;
public List<Book> findBookesById(int id){
return bookDao.findBookByCategoryId(id);
}
}
在這裏需要說明的是每一個使用註解加入到bean容器的對象它的id名稱會默認是類名首字符小寫的駝峯式命名,在使用@AutoWired時如果是service的impl需要注意。
測試
在Test
目錄下新建一個ServiceTest
類。如果沒有建立resource目錄,applicationContext.xml文件默認是在web文件夾下,就只能通過file的形式進行定位,但是我試了網上的好多方法最後的結果是tomcat無法加載這個xml文件。
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations={"applicationContext.xml"})
public class ServiceTest {
@Autowired
private CategoryService categoryService;
@Autowired
private BookService bookService;
@Test
public void TestCategoryService(){
System.out.println(categoryService.findAll());
}
@Test
public void TestBookService(){
System.out.println(bookService.findBookesById(1));
}
}
這裏需要導入junil和hamcrest的jar包。@ContextConfiguration指明從哪個文件構造ioc容器。
測試結果
controller開發
@Controller
@RequestMapping("/category")
public class CategoryController {
@Autowired
private CategoryService categoryService;
@RequestMapping("/view")
public String viewCategory(Model model){
List<Category> list = categoryService.findAll();
model.addAttribute("category",list);
return "main";
}
/*使用modelAndView*/
@RequestMapping("/modelview")
public ModelAndView showCategory(ModelAndView model){
List<Category> list = categoryService.findAll();
model.setViewName("main");
model.addObject("category",list);
return model;
}
}
@Controller
@RequestMapping("/book")
public class BookController {
@Autowired
private BookService bookService;
/*restful風格*/
@RequestMapping("/{id}")
@ResponseBody
public List<Book> showBookedByCategoryId(@PathVariable("id") int id){
return bookService.findBookesById(id);
}
/*常規方式
@RequestMapping("")
@ResponseBody
public List<Book> showBookCategoryId(@RequestParam("id") int id){
}
*/
}
使用@controller
將這個類加入容器,@RequestMapping
進行攔截url。
一般常見url的幾種風格有一下幾種:
- 常規方式
http://localhost:8080/book?id=1
- restful風格(
推薦
)
http://localhost:8080/book/1
如果是ajax請求json數據,可以使用@ResponseBody,將返回的對象以字符串的形式寫入body中,這裏需要引入三個jackson的jar,springmvc才能自動的將對象轉化爲字符串jackson-databind.jar
jackson-annotation.jar
jackson-core.jar
view開發
在view文件夾下新建main.jsp
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ page import="java.sql.DriverManager" %>
<%@ page import="java.sql.Connection" %>
<%@ page import="java.sql.Statement" %>
<%@ page import="java.sql.ResultSet" %>
<%@ page import="java.util.List" %>
<%--
Created by IntelliJ IDEA.
User: maoalong
Date: 2019/11/4
Time: 10:20
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<script type="text/javascript" src="/js/jquery.min.js"></script>
<link href="/css/bootstrap3.min.css" rel="stylesheet">
<link href="/css/main-style.css" rel="stylesheet">
<script type="text/javascript" src="/js/bootstrap3.min.js"></script>
<script src="/js/commons.js"></script>
<title>網上書店</title>
</head>
<body>
<div class="header">
<div class="container">
<div class="row">
<div class="login col-md-12">
<h1><a href="">歡迎來到<strong>我的</strong>書店</a>
<span style="color: red">.</span>
</h1>
</div>
</div>
<div class="row">
<div class="login col-md-3 col-md-offset-9">
<a class="login" href="" rel="tooltip" data-toggle="modal" data-target="#myModal">登錄</a>
<a class="register" href="" rel="tooltip" data_placement="bottom">註冊</a>
</div>
</div>
</div>
</div>
<div class="aside">
<div class="container">
<div class="row"> <%--下方左右div控制--%>
<div class="col-md-3"> <%--左側菜單div控制--%>
<ul class="nav nav-pills nav-stacked" id="categorylist">
<li class="nav-header">書籍類型</li>
<c:forEach items="${category}" var="category">
<li>
<a href="javascript:showBook(${category.id})">${category.name}</a>
</li>
</c:forEach>
</ul>
</div><%--左側菜單div控制--%>
</div>
</div>
</div>
<div id="book">
<%--<div class="col-md-9"><%–右側書本div控制–%>--%>
<%--<%--%>
<%--Object books = request.getAttribute("books");--%>
<%--List<Book> listBook = null;--%>
<%--if (books instanceof List) {--%>
<%--listBook =(List<Book>)books;--%>
<%--}--%>
<%--if(listBook!=null) {--%>
<%--for(Book book:listBook) {--%>
<%--String desc = book.getDescription();--%>
<%--if(desc.length() > 18) {--%>
<%--desc = desc.substring(1,18) + "...";--%>
<%--}--%>
<%--%>--%>
<%--<div class="col-sm-9 col-md-3">--%>
<%--<div class="thumbnail">--%>
<%--<img src="/images/book.jpeg"--%>
<%--alt="通用的佔位符縮略圖">--%>
<%--<div class="caption">--%>
<%--<h4><%=book.getName()%></h4>--%>
<%--<p><%=desc%></p>--%>
<%--<p>--%>
<%--<a href="#" class="btn btn-primary" role="button">--%>
<%--按鈕--%>
<%--</a>--%>
<%--<a href="#" class="btn btn-default" role="button">--%>
<%--按鈕--%>
<%--</a>--%>
<%--</p>--%>
<%--</div>--%>
<%--</div>--%>
<%--</div>--%>
<%--<%--%>
<%--}--%>
<%--}--%>
<%--%>--%>
<%--</div><%–右側書本div控制–%>--%>
</div>
<div class="modal fade" id="myModal" >
<div class="modal-dialog" style="width:550px;" >
<div class="modal-content">
<!-- 模態框的頭 -->
<div class="modal-header">
<h2 class="modal-title" id="myModalLabel" style="margin: 0 auto;font-weight: 300;font-family: '宋體'">登錄</h2>
</div>
<div class="modal-body">
<!-- 以下是登錄的form表單 -->
<form class="form-group" action="showID.jsp" method="post">
<div class="form-group">
<label>用戶名</label>
<input name="id" class="form-control" type="text" placeholder="請輸入用戶名">
</div>
<div class="form-group">
<label>密碼</label>
<input name="pwd" class="form-control" type="password" placeholder="請輸入密碼">
</div>
<div class="text-right">
<button class="btn btn-primary" type="submit">登錄</button>
<button class="btn btn-danger" data-dismiss="modal">取消</button>
</div>
</form>
</div>
</div>
</div>
</div>
</body>
<script language="JavaScript">
// function showCategory() {
// var xmlHttp = new XMLHttpRequest();
// xmlHttp.open("GET","/category",true);
// xmlHttp.onreadystatechange = function () {
// if(xmlHttp.readyState==4) {
// var data = xmlHttp.responseText;
// var obj = JSON.parse(data);
// obj = obj.categories;
// var listHtml = "<li class=\"nav-header\">書籍類別</li>\n" ;
// for(var i=0;i<obj.length;i++){
// listHtml += "<li>\n" +
// " <a href=\"javascript:showBook("+ obj[i].id + ")\">"+obj[i].name+"</a>\n" +
// " </li>"
// }
// document.getElementById("categorylist").innerHTML=listHtml;
// }
// }
// xmlHttp.send();
// }
function showBook(categoryID) {
var xmlHttp = new XMLHttpRequest();
xmlHttp.open("GET", "/book/"+categoryID, true);
xmlHttp.onreadystatechange = function () {
if (xmlHttp.readyState == 4) {
var data = xmlHttp.responseText;
var obj = JSON.parse(data);
var listbook = '';
for(var i = 0; i<obj.length;i++){
var bookname = obj[i].name;
var desc = obj[i].description;
if(desc.length > 20) {
desc = desc.substring(0,17)
}
listbook += `<div class="col-sm-9 col-md-3"><div class="thumbnail" ><img src="/images/book.jpeg"><div class="caption"><h4>
${bookname}</h4><p>${desc}</p><p><a href="#" class="btn btn-primary"role="button">加入購物車</a>
<a href="#" class="btn btn-default" role="button">查看詳情</a></p></div></div> </div>`;
}
document.getElementById("book").innerHTML = listbook;
}
}
xmlHttp.send();
}
</script>
</html>
static中引用的靜態文件
到這裏一個簡單的在線商城已經完成了,現在可以看下效果怎麼樣。配置你的tomcat服務器,啓動後在地址欄輸入:http://localhost:8080/category/view
點擊其中一種書籍類型,後臺的ajax函數會爲我們請求數據
我們不妨看看ajax返回的數據,結果是一個json字符串,爲了看得更清楚點可以使用postman軟件發送請求。可以看到返回的就是一個js的數組對象。
springboot版本的在線商城請參考idea搭建springboot項目