云笔记


Spring 事务管理

只读属性

对于单纯读取数据库操作, 可以设置readOnly=true, 可以提高数据的放效率.

@Transactional(readOnly=true)
public List<Map<String, Object>> listNotesInTrashBin(
String userId) throws UserNotFoundException {

事务的传播

业务过程重构时候需要业务方法调用业务方法, 这样就需要一个业务方法的事务传播到另外一个业务方法中, 整合为一个事务.

案例:

步骤:

  1. 创建数据表:

    create table cn_star (
    cn_star_id varchar(50),
    cn_user_id varchar(50),
    cn_stars int,
    primary key(cn_star_id)
    );
  2. 声明 StarsDao

    public interface StarsDao {
    Stars findStarsByUserId(String userId);
    int insertStars(Stars stars);
    int updateStars(Stars stars);
    }
  3. 声明SQL StarsMapper.xml

    <mapper namespace="cn.tedu.note.dao.StarsDao"><select id="findStarsByUserId"
    parameterType="string"
    resultType="cn.tedu.note.entity.Stars">
    select
    cn_star_id as id,
    cn_user_id as userId,
    cn_stars as stars
    from
    cn_star
    where
    cn_user_id = #{userId}
    </select>
    <insert id="insertStars"
    parameterType="cn.tedu.note.entity.Stars">
    insert into cn_star(
    cn_star_id,
    cn_user_id,
    cn_stars
    )values(
    #{id},
    #{userId},
    #{stars}
    )
    </insert>
    <update id="updateStars"
    parameterType="cn.tedu.note.entity.Stars">
    update cn_star
    set
    cn_stars = #{stars}
    where
    cn_user_id=#{userId} or
    cn_star_id=#{id}
    </update>
    </mapper>c
  4. 声明业务层接口方法 NoteService

    boolean addStars(String userId, int stars)
    throws UserNotFoundException;
  5. 实现方法 NoteServiceImpl

    @Transactional
    public boolean addStars(String userId, int stars)
    throws UserNotFoundException {
    if(userId==null||userId.trim().isEmpty()){
    throw new UserNotFoundException("ID空");
    }
    User user=userDao.findUserById(userId);
    if(user==null){
    throw new UserNotFoundException("木有人");
    }
    //检查是否已经有星了
    Stars st=starsDao.findStarsByUserId(userId);
    if(st==null){//如果没有星星
    String id = UUID.randomUUID().toString();
    st = new Stars(id, userId, stars);
    int n = starsDao.insertStars(st);
    if(n!=1){
    throw new RuntimeException("失败");
    }
    }else{//如果有星星,就在现有星星数量上增加
    int n = st.getStars()+stars;
    if(n<0){
    // n = 0;
    throw new RuntimeException("扣分太多!");
    }
    st.setStars(n);
    n = starsDao.updateStars(st);
    if(n!=1){
    throw new RuntimeException("失败");
    }
    }
    return true;
    }
  6. 测试: NoteServiceTest

    @Test
    public void testAddStars(){
    String userId="03590914-a934-4da9-ba4d-b41799f917d1";
    boolean b = service.addStars(userId, 5);
    System.out.println(b);
    b = service.addStars(userId, 6);
    System.out.println(b);
    }
  7. 重构 addNote方法, 实现添加笔记时候送星星功能, 进而实现事务的传播:

    @Transactional
    public Note addNote(String userId,
    String notebookId, String title)
    throws UserNotFoundException,
    NotebookNotFoundException {if(userId==null||userId.trim().isEmpty()){
    throw new UserNotFoundException("ID空");
    }
    User user=userDao.findUserById(userId);
    if(user==null){
    throw new UserNotFoundException("木有人");
    }
    if(notebookId==null||notebookId.trim().isEmpty()){
    throw new NotebookNotFoundException("ID空");
    }
    int n=notebookDao.countNotebookById(notebookId);
    if(n!=1){
    throw new NotebookNotFoundException("没有笔记本");
    }
    if(title==null || title.trim().isEmpty()){
    title="葵花宝典";
    }
    String id = UUID.randomUUID().toString();
    String statusId = "1";
    String typeId = "1";
    String body = "";
    long time=System.currentTimeMillis();
    Note note = new Note(id, notebookId,
    userId, statusId, typeId, title,
    body, time, time);
    n = noteDao.addNote(note);
    if(n!=1){
    throw new NoteNotFoundException("保存失败");
    }
    //当前的事务, 会传播到 addStart方法中
    //整合为一个事务!
    addStars(userId, 5);return note;
    }
  8. 测试...

事务传播(propagation)属性

重点掌握 Propagation.REQUIRED

  1. @Transactional(propagation=Propagation.REQUIRED)

    • 需要事务, 如果没有事务创建新事务, 如果当前有事务参与当前事务

  2. @Transactional(propagation=Propagation.MANDATORY)

    • 必须有事务, 如果当前没有事务就抛异常

  3. @Transactional(propagation=Propagation.NEVER)

    • 绝不, 绝对不能有事务, 如果在事务中调用则抛出异常

  4. @Transactional(propagation=Propagation.NESTED)

    • 嵌套, 必须被嵌套到其他事务中

  5. @Transactional(propagation=Propagation.NOT_SUPPORTED)

    • 不支持事务

  6. @Transactional(propagation=Propagation.SUPPORTS)

    • 支持事务, 如果没有事务也不会创建新事务

  7. @Transactional(propagation=Propagation.REQUIRES_NEW)

    • 必须是新事务, 如果有当前事务, 挂起当前事务并且开启新事务.

事务隔离属性

一共有4种, 一般采用 @Transactional(isolation=Isolation.READ_COMMITTED) 级别, 是并发性能和安全性折中的选择. 是大多数软件项目采用的隔离级别.

声明式事务

就是所有业务方法使用@Transactional, 如果是只读方法, 建议增加readOnly=true

面试题目:

Spring 声明式事务是如何实现的?
答案: 利用AOP技术实现.

文件的上载与下载

HTTP协议中文件是如何下载的

tctm-art-student-fe

根据HTTP1.1协议, 知道服务器向客户端传输数据如下:

HTTP/1.1 200 OK
Content-Type: image/png
Content-Length: 130数据内容

安装这个规则, 可以利用Servlet向客户端发送自定义图片:

  1. 声明Servlet

    public class ImageServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;
    protected void doGet(
    HttpServletRequest request,
    HttpServletResponse response)
    throws ServletException, IOException {
    //发送照片
    byte[] png = createPng();
    response.setContentType("image/png");
    response.setContentLength(png.length);
    //在消息body中发送消息数据
    response.getOutputStream().write(png);
    }
    /**
    * 创建一个图片, 并且编码为 png 格式, 返回
    * 编码以后的数据
    */
    private byte[] createPng() throws IOException{
    BufferedImage img =
    new BufferedImage(200, 80,
    BufferedImage.TYPE_3BYTE_BGR);
    //在图片上绘制内容
    img.setRGB(100, 40, 0xffffff);
    //将图片编码为PNG
    ByteArrayOutputStream out =
    new ByteArrayOutputStream();
    ImageIO.write(img, "png", out);
    out.close();
    byte[] png = out.toByteArray();
    return png;
    }
    }
  2. 配置Servlet

    <servlet>
    <description></description>
    <display-name>ImageServlet</display-name>
    <servlet-name>ImageServlet</servlet-name>
    <servlet-class>cn.tedu.note.web.ImageServlet</servlet-class>
    </servlet>
    <servlet-mapping>
    <servlet-name>ImageServlet</servlet-name>
    <url-pattern>/demoimg</url-pattern>
    </servlet-mapping>
  3. 测试

    http://localhost:8080/note/demoimg

    显示生产的图片

  4. 在网页中显示图片:

    <h1>自定义图片</h1>
    <p>
    Servlet 处理自定义图片
    <img alt="" src="demoimg">
    </p>

利用Spring MVC也可以动态生产图片:

  1. 添加控制器方法 UserController

    /*
    * @ResponseBody 注解会自动处理控制返回值
    * 1. 如果是JavaBean(数组,集合) 返回JSON
    * 2. 如果是byte数字, 则将byte数组直接装入
    * 响应消息的body
    */
    //produces="image/png"用于设置 content-type
    @RequestMapping(value="/image.do",
    produces="image/png")
    @ResponseBody
    public byte[] image() throws Exception{
    return createPng();
    }
    /**
    * 创建一个图片, 并且编码为 png 格式, 返回
    * 编码以后的数据
    */
    private byte[] createPng() throws IOException{
    BufferedImage img =
    new BufferedImage(200, 80,
    BufferedImage.TYPE_3BYTE_BGR);
    //在图片上绘制内容
    img.setRGB(100, 40, 0xffffff);
    //将图片编码为PNG
    ByteArrayOutputStream out =
    new ByteArrayOutputStream();
    ImageIO.write(img, "png", out);
    out.close();
    byte[] png = out.toByteArray();
    return png;
    }
  2. 在页面中显示图片:

    <p>
    Spring MVC 处理自定义图片
    <img alt="" src="user/image.do">
    </p>

根据RFC 2616 的 19.5.1 章节内容, 设置HTTP协议头, 就可以实现图片下载保存功能:

Content-Type: application/octet-stream
Content-Disposition: attachment; filename="fname.ext"
  1. 声明控制器方法 UserController

    @RequestMapping(value="/downloadimg.do",
    produces="application/octet-stream")
    @ResponseBody
    public byte[] downloadimg(
    HttpServletResponse res)
    throws IOException{
    //参考: 19.5.1 Content-Disposition
    //Content-Disposition: attachment; filename="fname.ext"
    res.setHeader("Content-Disposition",
    "attachment; filename=\"demo.png\"");
    return createPng();
    }
  2. 网页上设置下载链接

    <h1>下载图片</h1>
    <a href="user/downloadimg.do">图片</a>

Excel 文件的下载: 与下载图片一样, 只需要更换API生产文件数据就可以实现下载功能了.

  1. 导入POI API, 用于处理Excel文件

    <dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi</artifactId>
    <version>3.13</version>
    </dependency>
  2. 利用POI生成Excel文件数据:

    private byte[] createExcel()
    throws IOException{
    //创建工作簿
    HSSFWorkbook workbook=new HSSFWorkbook();
    //创建工作表
    HSSFSheet sheet=
    workbook.createSheet("Demo");
    //在工作表中创建数据行
    HSSFRow row = sheet.createRow(0);
    //创建行中的格子
    HSSFCell cell = row.createCell(0);
    cell.setCellValue("Hello World!");
    //将Excel文件保存为 byte 数组
    ByteArrayOutputStream out =
    new ByteArrayOutputStream();
    workbook.write(out);
    out.close();
    return out.toByteArray();
    }
  3. 利用Spring MVC控制器下载Excel:

    @RequestMapping(value="/excel.do",
    produces="application/octet-stream")
    @ResponseBody
    public byte[] excel(
    HttpServletResponse res)
    throws IOException{
    //参考: 19.5.1 Content-Disposition
    res.setHeader("Content-Disposition",
    "attachment; filename=\"demo.xls\"");
    return createExcel();
    }
  4. 在网页上连接下载控制器:

    <h1>下载Excel</h1>
    <a href="user/excel.do">Excel 文件</a>

上载文件

上载文件协议 tctm-art-student-fe

文件上载:

1. 客户端:

<h1>文件上载</h1>
<FORM ENCTYPE="multipart/form-data"
ACTION="user/upload.do" METHOD="POST">
File to process:<br>
<INPUT NAME="userfile1" TYPE="file"><br>
<INPUT NAME="userfile2" TYPE="file"><br>
<INPUT TYPE="submit" VALUE="Send File">
</FORM>

2. 服务器端:

  1. 导入 上载组件:

    <dependency>
    <groupId>commons-fileupload</groupId>
    <artifactId>commons-fileupload</artifactId>
    <version>1.3.2</version>
    </dependency>
  2. 配置上载解析器 spring-mvc.xml

    <bean id="multipartResolver"
    class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
    <!-- one of the properties available; the maximum file size in bytes -->
    <property name="maxUploadSize"
    value="10000000"/>
    <property name="defaultEncoding"
    value="UTF-8"/>
    </bean>
  3. 开发控制器:

    @RequestMapping("/upload.do")
    @ResponseBody
    public JsonResult upload(
    MultipartFile userfile1,
    MultipartFile userfile2) throws Exception{
    //Spring MVC 中可以利用 MultipartFile
    //接收 上载的文件! 文件中的一切数据
    //都可以从 MultipartFile 对象中找到//获取上再是原始文件名
    String file1 =
    userfile1.getOriginalFilename();
    String file2 =
    userfile2.getOriginalFilename();System.out.println(file1);
    System.out.println(file2);//保存文件的3种方法:
    //1. transferTo(目标文件)
    // 将文件直接保存到目标文件, 可以处理大文件
    //2. userfile1.getBytes() 获取文件的全部数据
    // 将文件全部读取到内存, 适合处理小文件!!
    //3. userfile1.getInputStream()
    // 获取上载文件的流, 适合处理大文件//保存的目标文件夹: /home/soft01/demo
    File dir = new File("D:/demo");
    dir.mkdir();File f1 = new File(dir, file1);
    File f2 = new File(dir, file2);//第一种保存文件
    //userfile1.transferTo(f1);
    //userfile2.transferTo(f2);//第三种 利用流复制数据
    InputStream in1 = userfile1.getInputStream();
    FileOutputStream out1 =
    new FileOutputStream(f1);
    int b;
    while((b=in1.read())!=-1){
    out1.write(b);
    }
    in1.close();
    out1.close();InputStream in2 = userfile2.getInputStream();
    FileOutputStream out2=
    new FileOutputStream(f2);
    byte[] buf= new byte[8*1024];
    int n;
    while((n=in2.read(buf))!=-1){
    out2.write(buf, 0, n);
    }
    in2.close();
    out2.close();return new JsonResult(true);
    }
  4. 测试


  1. 实现笔记列表导出到Excel功能

  2. 实现文件上载功能

jy-12-SPRINGMYBATIS02——云笔记09-刘苍松相关推荐

  1. jy-10-SPRINGMYBATIS01——MyBatis-程祖红/刘苍松

    目录: 1.day01-MyBatis-程祖红 2.day07-MyBatis-刘苍松 文件已上传分享 3.day08-SSM-刘苍松 文件已上传分享 @程祖红 1.day01-MyBatis (1) ...

  2. beego orm Error 1045 [ORM]2020/06/12 22:17:09 register db Ping `default`, Error 1045: Access denied

    [ORM]2020/06/12 22:17:09 register db Ping default, Error 1045: Access denied for user 'root'@'localh ...

  3. (2011.09始)大二全学期学习计划

    -------&&&&&&&------- 大二上学期计划变动(2011.09.09) --------&&&& ...

  4. 乐视生态世界发布会官方图文直播(2016年01月12日 15:00)

    2016年01月12日 13:10 生态世界即将开启!乐视将再度引领潮流,让更多人感受到生态的魅力.再一次颠覆,你准备好了吗?彻底焕新,我们来了!1月12日15:00,乐视生态世界发布会全程直播,敬请 ...

  5. 鞍山树人计算机学校宿舍,南开大学校务公报2016年第12期-信息公开.pdf

    南开大学校务公报2016年第12期-信息公开 2016 年第12 期总第125 期 (新生特刊) 南开大学办公室编 2016 年10 月30 日 南开大学校务公报20 16 年第12 期 目 录 开学 ...

  6. oracle 查询一年12个月的sql,获取今年在内的前几年、后几年

    -- 一年12月的sql select to_char(sysdate, 'yyyy-') || lpad(level, 2, 0) datevaluefrom dual connect by lev ...

  7. 百度刘超走进天津大学

    前百度总监刘超98年以全国第六名考入清华美院,如今带HCI学生首秀油画技法    2019年12月25日刘超老师带领同学们圣诞的cosplay party引起极大轰动,当晚互联网文化刷爆天津大学生朋友 ...

  8. MySQL数据库基本命令

    基本数据命令 – 01.查看mysql服务器中所有数据库 show databases; – 02.进入某一数据库(进入数据库后,才能操作库中的表和表记录) – 语法:USE 库名; use db10 ...

  9. 第三阶段:Web前端:01Web(HTML、CSS、JavaScript)

    转载自:国彬老师:https://shimo.im/docs/47kgJm9bMdiLO5qV/read 课程介绍:一.二.三 一.Web前端: 学习如何搭建页面,如何美化页面,如何给页面添加动态效果 ...

  10. 超详细数据库笔记!!!!!!还带55道练习题

    数据库的基本概念 1. 数据库的英文单词: DataBase 简称 : DB 2. 什么数据库?* 用于存储和管理数据的仓库.3. 数据库的特点:1. 持久化存储数据的.其实数据库就是一个文件系统2. ...

最新文章

  1. java catch getm_Java------异常处理机制
  2. 老司机带你用 Go 语言实现 MapReduce 框架
  3. 实战:从Mysql数据库frm文件中,提取表结构创建SQL语句
  4. 存定期还能加钱进去吗_还要去银行存定期吗?六大行叫停靠档计息个人存款产品...
  5. [渝粤教育] 中国地质大学 思想道德修养与法律基础 复习题
  6. 异步社区本周(3.26-4.1)半价电子书
  7. 最新O泡易支付系统源码-源码全解密,无后门,本地资源化
  8. python14张图下载_Python网络爬虫入门(三)—— 做个简陋的pixabay 图片下载器 (附源码)...
  9. hadoop3.3.0集群搭建(详细教程)
  10. 修改服务器线路,介绍几种常见的网络服务器线路
  11. 设计模式之装饰器模式
  12. 『单片机原理』程序存储器的结构
  13. 阿里云播放器AliyunPlayer的走马灯组件的位置
  14. .axf文件_Keil开发环境如何生成BIN文件
  15. 等额本金和等额本息是怎么算出来的
  16. [fjwc2015]Screen [从hzw神犇那里扒来的题]
  17. 首次去中心化抢劫?近2亿美元损失:跨链桥Nomad 被攻击事件分析
  18. 时序数据库-Timescale 在Windows上的安装
  19. ANE-IOS与AS的互通
  20. 【Java例题】2.8 解一元二次方程

热门文章

  1. HANA 如何创建XS Job来完成定时任务
  2. 大数据—— Clickhouse 介绍与引擎的使用
  3. 【31】poisoned TLP导致的MCE问题
  4. 牛逼,我用Python做了一个word、PPT水印添加器!还带加密功能!
  5. arcgis中字段的融合_利用ArcGis进行地理处理之三(融合)
  6. 跑步耳机哪款好用,排行前五的运动耳机推荐
  7. 软件测试常见英文单词汇总
  8. 哈工大计算机科学与技术硕士培养方案,计算机科学与技术学科硕士研究生培养方案哈工大计算机学院[文].pdf...
  9. micropython 进阶小实验 如何用单片机制作鞋码匹配仪
  10. stm32 F40x CCM数据区的使用