[牛客网中级项目]第三章 数据库交互mybatis集成(笔记)

1. 创建数据库

1.创建toutiao数据库。
2.创建需要的表。现在只创建User,News表。

UserConmmentMessageNews
idididid
namecontentformiidtitle
passworduseridtoidlink
saltcreated_datecontentimage
head_urlnews_idconversation_idlike_count
created_datecomment_count
user_id
created_date

2. 项目里连接数据库

1.配置环境:
在上一章搭建的项目里继续,加入依赖:

<dependency>
   <groupId>org.mybatis.spring.boot</groupId>
   <artifactId>mybatis-spring-boot-starter</artifactId>
   <version>1.1.1</version>
</dependency>

<dependency>
   <groupId>mysql</groupId>
   <artifactId>mysql-connector-java</artifactId>
   <scope>runtime</scope>
</dependency>

2.配置数据库链接,放在资源下的application.properties里。在资源里加入配置文件mybatis-config.xml。
application.properties:

spring.datasource.url=jdbc:mysql://localhost:3306/toutiao?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=UTC
spring.datasource.username=root
spring.datasource.password=123
mybatis.config-location=classpath:mybatis-config.xml

mybatis-config.xml:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>

    <settings>
        <!-- Globally enables or disables any caches configured in any mapper under this configuration -->
        <setting name="cacheEnabled" value="true"/>
        <!-- Sets the number of seconds the driver will wait for a response from the database -->
        <setting name="defaultStatementTimeout" value="3000"/>
        <!-- Enables automatic mapping from classic database column names A_COLUMN to camel case classic Java property names aColumn -->
        <setting name="mapUnderscoreToCamelCase" value="true"/>
        <!-- Allows JDBC support for generated keys. A compatible driver is required.
        This setting forces generated keys to be used if set to true,
         as some drivers deny compatibility but still work -->
        <setting name="useGeneratedKeys" value="true"/>
    </settings>

    <!-- Continue going here -->

</configuration>

3. 基于注解配置

3.1 定义与表对应的类

在model里创建News.class和User.class。
News.class:

package com.nowcoder.toutiao.model;

import java.util.Date;

public class News {
    
    private int id;
    private String title;
    private String link;
    private String image;
    private int likeCount;
    private int commentCount;
    private int userId;
    private Date createdDate;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String getLink() {
        return link;
    }

    public void setLink(String link) {
        this.link = link;
    }

    public String getImage() {
        return image;
    }

    public void setImage(String image) {
        this.image = image;
    }

    public int getLikeCount() {
        return likeCount;
    }

    public void setLikeCount(int likeCount) {
        this.likeCount = likeCount;
    }

    public int getCommentCount() {
        return commentCount;
    }

    public void setCommentCount(int commentCount) {
        this.commentCount = commentCount;
    }

    public int getUserId() {
        return userId;
    }

    public void setUserId(int userId) {
        this.userId = userId;
    }

    public Date getCreatedDate() {
        return createdDate;
    }

    public void setCreatedDate(Date createdDate) {
        this.createdDate = createdDate;
    }
}

User.class:

package com.nowcoder.toutiao.model;

public class User {

    private int id;
    private String name;
    private String password;
    private String salt;
    private String headUrl;

    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 String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getSalt() {
        return salt;
    }

    public void setSalt(String salt) {
        this.salt = salt;
    }

    public String getHeadUrl() {
        return headUrl;
    }

    public void setHeadUrl(String headUrl) {
        this.headUrl = headUrl;
    }
}

3.2 建立dao包

dao(持久层)包内是与数据库进行交互的程序。(controller(web层)是与网页,service(服务层/业务层)是dao和controller中间那层)
1.创建UserDAO.class

package com.nowcoder.toutiao.dao;

import com.nowcoder.toutiao.model.User;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Mapper;
// 一个简单的插入
@Mapper  // 表示这个接口是与数据库一一匹配的
public interface UserDAO {
    // 减少代码的重复写;(注意空格,不要少空格)
    String TABLE_NAME = "user";
    String INSERT_FIELD = " name, password, salt, head_url ";
    String SELECT_FEILDS = " id, name, password, salt, head_url ";

    // 通过注解实现的
    // @Insert({"insert into user(name,password,salt,head_url)values()"})
    @Insert({"insert into ",TABLE_NAME ,"(", INSERT_FIELD, ")" +
            "values(#{name}, #{password},#{salt}, #{headUrl})"})
    int addUser(User user);

}

2.写一个测试用例
InitDatabaseTest.class:

package com.nowcoder.toutiao;

import com.nowcoder.toutiao.dao.UserDAO;
import com.nowcoder.toutiao.model.User;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.SpringApplicationConfiguration;
import org.springframework.test.context.jdbc.Sql;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;

import java.util.Random;

@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = ToutiaoApplication.class)
@Sql("/init-schema.sql")  //创建文件中的表
public class InitDatabaseTests {

   @Autowired
   UserDAO userDAO;

   @Test
   public void contextLoads() {
      Random random = new Random();
      for (int i=0;i<11;i++){
         User user = new User();
         user.setName(String.format("USER%d",i));
         user.setPassword("");
         user.setSalt("");
         user.setHeadUrl(String.format("http://images.nowcoder.com/head/%dt.png",random.nextInt(1000)));
         userDAO.addUser(user);
      }

   }

}

这里可能报错:
(1)第二章的IndexController里有用到User,但是这里User改变了,所以把它里面用到的注释掉。
(2)出现mysql相关的错误,password那个。是因为它用的老版本的5.x.x,和要连接的数据库的版本不同,我用的8.0.17的,把依赖里的版本改为8.0.17 。
(2019.8.2新的)还是数据库的问题。
org.springframework.transaction.CannotCreateTransactionException: Could not open JDBC Connection for transaction; nested exception is java.sql.SQLException: Access denied for user ‘root’@‘localhost’ (using password: YES)
之前出现这个问题,改了依赖版本。还是不行,想起上次查了别人说的改数据库的权限。但是数据库的权限其实是有的,不用改,改了也没用。。然后上次最后解决办法是重新安装了数据库。。。这次还没有改 换了数据库,装了一个5.6的版本MYSQL,按照这个安装新的MYSQL:添加链接描述
因为安装的时候MYSQL端口号设置为了3307,在application.properties里的端口号要记得改。然后就运行成功了。

3.在UserDAO里继续添加其他方法:select,update,delete。

package com.nowcoder.toutiao.dao;

import com.nowcoder.toutiao.model.User;
import org.apache.ibatis.annotations.*;

@Mapper  // 表示这个接口食欲数据库一一匹配的
public interface UserDAO {
    // 减少代码的重复写;(注意空格,不要少空格)
    String TABLE_NAME = "user";
    String INSERT_FIELD = " name, password, salt, head_url ";
    String SELECT_FEILDS = " id, name, password, salt, head_url ";

    // 通过注解
    // @Insert({"insert into user(name,password,salt,head_url)values()"})
    @Insert({"insert into ",TABLE_NAME ,"(", INSERT_FIELD, ")" +
            "values(#{name}, #{password},#{salt}, #{headUrl})"})
    int addUser(User user);

    @Select({"select ", SELECT_FEILDS, " from ",TABLE_NAME, " where id=#{id}"})
    User selectById(int id);

    @Update({"update ",TABLE_NAME, " set password =#{password} where id=#{id}"})
    void updatePassword(User user);

    @Delete({"delete from ", TABLE_NAME, " where id=#{id}"})
    void deleteById(int id);
    
}

测试:

package com.nowcoder.toutiao;

import com.nowcoder.toutiao.dao.UserDAO;
import com.nowcoder.toutiao.model.User;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.SpringApplicationConfiguration;
import org.springframework.test.context.jdbc.Sql;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;


import java.util.Random;

@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = ToutiaoApplication.class)
@Sql("/init-schema.sql")  //创建文件中的表
public class InitDatabaseTests {

   @Autowired
   UserDAO userDAO;

   @Test
   public void initTest() {
      Random random = new Random();
      for (int i=0;i<11;i++){
         User user = new User();
         user.setName(String.format("USER%d",i));
         user.setPassword("");
         user.setSalt("");
         user.setHeadUrl(String.format("http://images.nowcoder.com/head/%dt.png",random.nextInt(1000)));
         userDAO.addUser(user);

         user.setPassword("new password");
         userDAO.updatePassword(user);
      }
      Assert.assertEquals("new password",userDAO.selectById(1).getPassword());
      userDAO.deleteById(1);
      Assert.assertNull(userDAO.selectById(1));
   }

}

4.创建UserDAO.class。用基于xml的方式。
用xml写的话可以写一些比较复杂的逻辑操作,用注解的话使用比较简单。

package com.nowcoder.toutiao.dao;

import com.nowcoder.toutiao.model.News;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;

import java.util.List;

@Mapper
public interface NewsDAO {
    String TABLE_NAME = "news";
    String INSERT_FIELD = " title, link, image, like_count, comment_count, user_id, created_date ";
    String SELECT_FEILDS = " id, title, link, image, like_count, comment_count, user_id, created_date ";

    // 通过注解配置:
    @Insert({"insert ", " into ", TABLE_NAME, "(", INSERT_FIELD,") " +
            "values(#{title}, #{link}, #{image}, " +
            "#{likeCount}, #{commentCount}, #{userId}, #{createdDate})"})
    int addNews(News news);


    //通过xml配置:(xml配置:放在resource的相同包目录下定义的同名xml)
    List<News> selectByUserIdAndOffset(@Param("userId") int userId,
                                       @Param("offset") int offset,
                                       @Param("limit") int limit);
}

注意:在resource目录下创建相同包目录时,要用new directory一个一个建,比如说先建com路径,再在里面建nowcoder路径。如果一次性输入com.nowcoder.xxxx.xxx,这时建立的路径上只有一个文件夹,该文件夹名字就是com.nowcoder.xxxx.xxx,而不是我们想要的包含子文件的com文件夹。

创建xml配置文件:NewsDAO.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="com.nowcoder.toutiao.dao.NewsDAO">
    <sql id="table">news</sql>
    <sql id="selectFields">id,title, link, image, like_count, comment_count,created_date,user_id
    </sql>
    <select id="selectByUserIdAndOffset" resultType="com.nowcoder.toutiao.model.News">
        SELECT
        <include refid="selectFields"/>
        FROM
        <include refid="table"/>

        <if test="userId != 0">
            WHERE user_id = #{userId}
        </if>
        ORDER BY id DESC
        LIMIT #{offset},#{limit}
    </select>
</mapper>

测试:

package com.nowcoder.toutiao;

import com.nowcoder.toutiao.dao.NewsDAO;
import com.nowcoder.toutiao.dao.UserDAO;
import com.nowcoder.toutiao.model.News;
import com.nowcoder.toutiao.model.User;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.SpringApplicationConfiguration;
import org.springframework.test.context.jdbc.Sql;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;


import javax.xml.crypto.Data;
import java.util.Date;
import java.util.Random;

@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = ToutiaoApplication.class)
@Sql("/init-schema.sql")  //创建文件中的表
public class InitDatabaseTests {

   @Autowired
   UserDAO userDAO;

   @Autowired
   NewsDAO newsDAO;

   @Test
   public void initDataTest() {
      Random random = new Random();
      for (int i=0;i<11;i++){
         User user = new User();
         user.setName(String.format("USER%d",i));
         user.setPassword("");
         user.setSalt("");
         user.setHeadUrl(String.format("http://images.nowcoder.com/head/%dt.png",random.nextInt(1000)));
         userDAO.addUser(user);

         News news = new News();
         news.setTitle(String.format("TITLE:{%d}",i));
         news.setLink(String.format("http://www.nowcoder.com/%d.html",i));
         news.setImage(String.format("http://images.nowcoder.com/head/%dm.png",random.nextInt(1000)));
         news.setLikeCount(i+1);
         news.setCommentCount(i);
         news.setUserId(i+1);
         Date date = new Date();
         date.setTime(date.getTime()+1000*3600*i*5);
         news.setCreatedDate(date);
         newsDAO.addNews(news);

         user.setPassword("new password");
         userDAO.updatePassword(user);
      }
      Assert.assertEquals("new password",userDAO.selectById(1).getPassword());
      userDAO.deleteById(1);
      Assert.assertNull(userDAO.selectById(1));
   }

}

3.3 创建service类

创建一个UserService.class:(为了在controller可以调用该服务)

package com.nowcoder.toutiao.service;

import com.nowcoder.toutiao.dao.UserDAO;
import com.nowcoder.toutiao.model.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.jws.soap.SOAPBinding;

@Service
public class UserService {

    @Autowired
    private UserDAO userDAO;

    public User getUser(int id){
        return userDAO.selectById(id);
    };

}

创建一个NewsService.class:

package com.nowcoder.toutiao.dao;

import com.nowcoder.toutiao.model.News;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;

import java.util.List;

@Mapper
public interface NewsDAO {
    String TABLE_NAME = "news";
    String INSERT_FIELD = " title, link, image, like_count, comment_count, user_id, created_date ";
    String SELECT_FEILDS = " id, title, link, image, like_count, comment_count, user_id, created_date ";

    // 通过注解配置:
    @Insert({"insert ", " into ", TABLE_NAME, "(", INSERT_FIELD,") " +
            "values(#{title}, #{link}, #{image}, " +
            "#{likeCount}, #{commentCount}, #{userId}, #{createdDate})"})
    int addNews(News news);


    //通过xml配置:(xml配置:放在resource的相同包目录下定义的同名xml)
    List<News> selectByUserIdAndOffset(@Param("userId") int userId,
                                       @Param("offset") int offset,
                                       @Param("limit") int limit);
}

3.4 建立主页

3.4.1 在controller建立HomeCotroller.class:

package com.nowcoder.toutiao.controller;

import com.nowcoder.toutiao.service.NewsService;
import com.nowcoder.toutiao.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import javax.servlet.http.HttpSession;

@Controller
public class HomeController {
    @Autowired
    NewsService newsService;

    @Autowired
    UserService userService;

    @RequestMapping(path={"/","/home"},method = {RequestMethod.GET, RequestMethod.GET})
    public String home(HttpSession session){
        return "home";
    }

}

3.4.2 把home.html放到resource的templates下。把其他文件放进statics下。

3.4.3 修改application.properties:

加入了强制用html类型

spring.datasource.url=jdbc:mysql://localhost:3306/toutiao?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=UTC
spring.datasource.username=root
spring.datasource.password=123
mybatis.config-location=classpath:mybatis-config.xml
#logging.level.root=DEBUG
spring.velocity.suffix=.html
spring.velocity.cache=false
#spring.velocity.toolbox-config-location=toolbox.xml

3.4.4 运行ToutiaoApplication里的main函数,出错:

在这里插入图片描述
下面的没截了。
原因时该端口被占用了?参考:
https://blog.csdn.net/zmq52007/article/details/81332450
更改端口。在application.properties里加入server.port=(新的端口号,比如8090)
此时再运行函数,没有报错。

3.4.5 再访问该网页

网页只有头部和底部的,中间是loading。(如果出现没有home.html资源,那就clean一下再运行:在这里插入图片描述)

出现

2019-08-09 15:39:53.568 ERROR 8804 --- [nio-8090-exec-2] org.apache.velocity                      : ResourceManager : unable to find resource 'error.html' in any resource loader.

因为此时还没写完(= =b)。继续写homecontroller。

3.4.6 homecontroller:

package com.nowcoder.toutiao.controller;

import com.nowcoder.toutiao.model.News;
import com.nowcoder.toutiao.model.User;
import com.nowcoder.toutiao.model.ViewObject;
import com.nowcoder.toutiao.service.NewsService;
import com.nowcoder.toutiao.service.UserService;
import org.apache.catalina.LifecycleState;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import javax.servlet.http.HttpSession;
import java.util.ArrayList;
import java.util.List;

@Controller
public class HomeController {
    @Autowired
    NewsService newsService;

    @Autowired
    UserService userService;

    @RequestMapping(path={"/","/home"},method = {RequestMethod.GET, RequestMethod.GET})
    public String home(Model model){

        // 把所有的资讯拷过来
        List<News> newsList = newsService.getLatestNews(0,0,10);

        List<ViewObject> vos = new ArrayList<>();
        for (News news:newsList){
            ViewObject vo = new ViewObject();
            vo.set("news",news);
            vo.set("user",userService.getUser(news.getUserId()));
            vos.add(vo);
        }
        model.addAttribute("vos", vos);

        return "home";
    }

}

3.4.7 使用ViewObject/DateTool

ViewObject:方便传递任何数据到Velocity,也是一个model。
DateTool:Velocity自带工具类导入

导入ViewObject.class:

package com.nowcoder.toutiao.model;

import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

/**
 * Created by rainday on 16/6/30.
 */
public class ViewObject {
    private Map<String, Object> objs = new HashMap<String, Object>();
    public void set(String key, Object value) {
        objs.put(key, value);
    }

    public Object get(String key) {
        return objs.get(key);
    }
}

导入toolbox:

<toolbox>
    <tool>
        <key>date</key>
        <scope>application</scope>
        <class>org.apache.velocity.tools.generic.DateTool</class>
    </tool>
</toolbox>

修改application.properties,加入:

spring.velocity.toolbox-config-location=toolbox.xml

3.4.8 修改home.html

俺也不懂,俺什么都不知道。直接复制他的代码,不知道怎么用的。
这时再运行主页,中间就有内容了,只是有些地方还不对,因为后面还要继续修改。

1.运行主页,出现错误:

Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed;

在网上搜的方法:
(1)model类全都实现Serializable接口,但是依然报这个错。x
(2)自己把home.html删了后重加。。然后报新错了:
在这里插入图片描述
但是这个不影响功能,不管他。
(3)参考:https://blog.csdn.net/lgq2016/article/details/89094281
发现在pom里少加了依赖。

<dependency>
   <groupId>org.apache.velocity</groupId>
   <artifactId>velocity-tools</artifactId>
</dependency>

加入后,运行主页成功。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值