SpringMVC详解
@RequestMapping详解
RequestMapping是一个用来处理请求地址映射的注解,可用于类或方法上。用于类上,表示类中的所有响应请求的方法都是以该地址作为父路径。这句话,太熟悉了。
一. RequestMapping路径详解
(1)首先springmvc.xml配置
<!-- 定义跳转的文件的前后缀 ,视图模式配置--> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <!-- 这里的配置我的理解是自动给后面action的方法return的字符串加上前缀和后缀,变成一个 可用的url地址 --> <property name="prefix" value="/WEB-INF/jsp/" /> <property name="suffix" value=".jsp" /> </bean>
(2)Controller 类
import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.servlet.ModelAndView; @Controller @RequestMapping("/jsp") public class RequestController { public static final String SUCCESS="success"; @RequestMapping("/login1") public void hello(){ System.out.println("hello world"); } /*第一点 *1:@RequestMapping定义在类上,那就相当于根目录 *2:@RequestMapping定义在方法上,那就相当于相对于类定义处的URL。 * 上面代码在类定义处指定映射为"/jsp",在hello()方法处指定为"/login1"。 * 那么hello()方法的URL映射地址为:http://localhost:8080/ssm/jsp/login1 * ssm指的是你项目的名称 */ /*第二点 * 1.@RequestMapping在类上定义不是必须的,如上如果我只在方法上定义@RequestMapping("/jsp/login1") * 那么它同样能访问上面的URL映射地址。 * 2.@RequestMapping的默认属性为value,所以@RequestMapping(value="/login1")和@RequestMapping("/login1")是等价的。 */ @RequestMapping("/login2") public String getModel(){ System.out.println("hello world"); return SUCCESS; } /*第三点:需要返回界面 *1.这个return success;加上springMVC配置的路径 * 那么它返回的路径是: * http://localhost:8080/ssm/WEB-INF/jsp/success.jsp */ @RequestMapping(value="/jsp/login3") public ModelAndView paramBind(){ ModelAndView modelAndView = new ModelAndView(); //传到界面的数据 modelAndView.addObject("date", "nihao"); modelAndView.setViewName(SUCCESS); return modelAndView; } /*第四点:返回界面同时带上数据 * 1.好多时候,我们要的不是跳转界面,而是能够把后台的数据传到前端去 * modelAndView.addObject放的就是你要传的数据 * modelAndView.setViewName返回路径名称 * 所以它的返回路径和上面一样 */ /*第五点:void类型无返回值跳转 * 1.根据上面无返回值那么它最终会跳转到 * http://localhost:8080/ssm/WEB-INF/jsp/jsp/login1.jsp * 原则: * prefix+类路径(类级别的mapping注解)+方法路径(方法级别的mapping注解)+prefix */ }
二.RequestMapping参数详解
请求参数的作用是使得请求的映射更加精细。
RequestMapping注解有六个属性,下面我们把她分成三类进行说明
value:定义处理方法的请求的 URL 地址。(重点)
method:定义处理方法的 http method 类型,如 GET、POST 等。(重点)
params: 定义请求的 URL 中必须包含的参数。或者不包含某些参数。(了解)
headers: 定义请求中 Request Headers 必须包含的参数。或者不包含某些参数。(了解)
下面也用个Controller 类来说明
1. Controller
@Controller @RequestMapping("/hello") public class TestController { public static final String SUCCESSS="successs"; /** * post动作请求的测试 */ @RequestMapping(method=RequestMethod.POST,value="/login1") public String testMethodPost(){ return SUCCESSS; } /** * 测试url中带参数(未测试请求头信息) */ //url http://localhost:8080/ssm/hello/login2?username=zhangsan&password=123&sex=2 @RequestMapping(value="/login2", params={"username","sex!=1","password=123"}, method=RequestMethod.GET) public String testHeadersAndParams(){ return SUCCESSS; } /** * PathVariable 映射 URL 绑定占位 ( 映射URL路径里面的变量) * * 用Integer会比int严谨 */ //http://localhost:8080/ssm/hello/login3/5 @RequestMapping(value="/login3/{id}",method=RequestMethod.GET) public String testPathVariable(@PathVariable("id") Integer id){ System.out.println("id:"+id); return SUCCESSS; } // http://localhost:8080/ssm/hello/login4/str @RequestMapping(value="/login4/{name}",method=RequestMethod.GET) public String testPathVariable2(@PathVariable("name") String name){ System.out.println("name :"+name); return SUCCESSS; } /** * 如果在方发上@RequestMapping()没有任何参数,那它就代表类上的value请求地址 * */ // http://localhost:8080/ssm/hello.jsp @RequestMapping() public String test(){ return SUCCESSS; } }
一. 有哪些绑定数据的注解:
1.@RequestParam,绑定单个请求数据,可以是URL中的数据,表单提交的数据或上传的文件;
2.@PathVariable,绑定URL模板变量值;
3.@CookieValue,绑定Cookie数据;
4.@RequestHeader,绑定请求头数据;
5.@ModelAttribute,绑定数据到Model;
6.@SessionAttributes,绑定数据到Session;
7.@RequestBody,用来处理Content-Type不是application/x-www-form-urlencoded编码的内容,例如application/json, application/xml等;
8.@RequestPart,绑定“multipart/data”数据,并可以根据数据类型进项对象转换;
二.@RequestParam讲解
首先说明,项目的框架和架包我直接用的是smm框架整合的内容,我是在这个基础上进行操作,先看我jsp放置。
(1)先看Controller层
import javax.servlet.http.HttpServletRequest; import org.springframework.stereotype.Controller; import org.springframework.web.bind.ServletRequestUtils; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartHttpServletRequest; import org.springframework.web.servlet.ModelAndView; @Controller public class ParamController { /** * GET请求 */ @RequestMapping(value="/jsp/paramdate", method = {RequestMethod.GET}) public ModelAndView paramBind(){ ModelAndView modelAndView = new ModelAndView(); //因为我这边指定是post请求,所以不会走到这里,所以haha.jsp也没有写 modelAndView.setViewName("haha"); return modelAndView; } /** * POST请求 */ @RequestMapping(value="/jsp/paramdate", method = {RequestMethod.POST}) public ModelAndView paramBind(HttpServletRequest request, @RequestParam("urlParam") String urlParam, @RequestParam("formParam")
String formParam, @RequestParam("formFile") MultipartFile formFile){ //通过注解直接获得 ModelAndView modelAndView = new ModelAndView(); modelAndView.addObject("urlParam", urlParam); modelAndView.addObject("formParam", formParam); modelAndView.addObject("formFileName", formFile.getOriginalFilename()); //如果不用注解获得数据,我们也可以手动获取 String urlParam1 = ServletRequestUtils.getStringParameter(request, "urlParam", null); String formParam1 = ServletRequestUtils.getStringParameter(request, "formParam", null); MultipartFile formFile1 = ((MultipartHttpServletRequest) request).getFile("formFile"); modelAndView.addObject("urlParam1", urlParam1); modelAndView.addObject("formParam1", formParam1); modelAndView.addObject("formFileName1", formFile1.getOriginalFilename()); //setViewName代表返回界面名称 modelAndView.setViewName("return"); return modelAndView; } }
(2)开始的start.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <html> <head> </head> <body> <form action="paramdate?urlParam=你好" method="post" enctype="multipart/form-data"> <input type="text" name="formParam" /><br/> <input type="file" name="formFile" /><br/> <input type="submit" value="Submit" /> </form> </body> </html>
界面
(3)返回return.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <html> <head> </head> <body> 注解获取数据:<br/><br/> ${urlParam}<br/> ${formParam}<br/> ${formFileName}<br/><br/><br/><br/> 手动获取数据:<br/><br/> ${urlParam1}<br/> ${formParam1}<br/> ${formFileName1}<br/> </body> </html>
界面
通过这个小案例,我们通过注解和非注解的方式,把前段界面的值传到后端,在从后端传到前段。
思考:我们在实际开发中,在前段往后段传值的时候,后端一个一个获取值再放到Model实体中,还是太麻烦。别担心,我们不需要把数据绑定到一个个变量然后在对model赋值,只需要把model加入相应的action参数(这里不需要指定绑定数据的注解)Spring MVC会自动进行数据转换并绑定到model对象上,一切就是这么简单。
三.通过实体获取前端值
(1)建立User实体
public class User { private String name; private String password; /*提供set和get方法,toString方法*/ }
(2)建立Controller类
import javax.servlet.http.HttpServletRequest; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.RequestMapping; import com.ssm.model.User; @Controller public class UsersController { @RequestMapping("/jsp/loging") public void getUser(HttpServletRequest request, Model model,User user){ User users=user; System.out.println(users.getName()+"--"+users.getPassword()); } }
(3)开始loging.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!-- 如何要使用SpringMVC标签,那么一定要添加下面这个taglib --> <%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %> <!-- 如果你要使用model进行赋值,那就需要指明哪个model,而且id中的值要和下面值一致,不然会报错 --> <!-- Neither BindingResult nor plain target object for bean name 'users' available as request attribute --> <jsp:useBean id="user" class="com.ssm.model.User" scope="request"/> <html> <body> <form:form action="loging" modelAttribute="user" method="post"> 用户名:<form:input path="name"/><br/> 密 码:<form:password path="password"/><br/> <input type="submit" value="Submit" /> </form:form> </body> </html> <!-- 还有如果你的form表单中,path中的名字,在model中没有也会报错,比如我加一个names,当加载页面时报错 --> <!-- Invalid property 'names' of bean class [com.ssm.model.User]: Bean property 'names' is not readable -->
界面 (密码123)
(4)最后我们在后台看我们打印的那条数据
已经成功,直接把属性注入到了user中。
对pdf模板添加文本域
使用Adobe Acrobat Pro软件,选择表单,就可以添加文本域很简单。这里也可以设置字体大小,是否换行等
第二步、pom文件导入相关jar包
<!-- 注意:我一开始把这个放到pom.xml文件中,发现报错了,原因是我的本地mevan库中没有5.5.10版的,只有5.1.1和5.1.3于是我在网上下了个,再放到本地库,更新下项目就可以了 --> <!-- itext 图片转pdf --> <dependency> <groupId>com.itextpdf</groupId> <artifactId>itextpdf</artifactId> <version>5.5.10</version> </dependency>
第三步,把pdf和照片素材放到项目中
这里我在resources下面新建了pdf文件夹,放到这里面
第四步、PdfController.java
import java.io.OutputStream; import java.io.UnsupportedEncodingException; import java.net.URLEncoder; import java.util.HashMap; import java.util.Map; import javax.servlet.http.HttpServletResponse; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import com.itextpdf.text.Image; import com.itextpdf.text.Rectangle; import com.itextpdf.text.pdf.AcroFields; import com.itextpdf.text.pdf.BaseFont; import com.itextpdf.text.pdf.PdfContentByte; import com.itextpdf.text.pdf.PdfReader; import com.itextpdf.text.pdf.PdfStamper; @Controller @RequestMapping("/jsp/exportpdf") public class PdfController { @RequestMapping public String pdfexport(HttpServletResponse response) { // 指定解析器 System.setProperty("javax.xml.parsers.DocumentBuilderFactory", "com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderFactoryImpl"); String filename = "resume.pdf"; response.setContentType("application/pdf"); try {
//设置文件头:最后一个参数是设置下载文件名(这里我们叫:个人简历.pdf) response.setHeader("Content-Disposition", "attachment;fileName=" + URLEncoder.encode("个人简历.pdf", "UTF-8")); } catch (UnsupportedEncodingException e1) { e1.printStackTrace(); } OutputStream os = null; PdfStamper ps = null; PdfReader reader = null; try { os = response.getOutputStream(); // 生成的新文件路径 ,这里指页面 /** * class.getResource("/") --> 返回class文件所在的顶级目录,一般为包名的顶级目录 * 在这个目录中src/main/java和src/main/resources和src/test/java都是属于顶级目录 * 这里pdf/就属于顶级目录下的子目录了 * */ // 2 读入pdf表单 reader = new PdfReader(PdfController.class.getResource("/pdf/") + "resume.pdf"); // 3 根据表单生成一个新的pdf ps = new PdfStamper(reader, os); // 4 获取pdf表单中所有字段 AcroFields form = ps.getAcroFields(); // 5给表单添加中文字体 这里采用系统字体。不设置的话,中文可能无法显示 BaseFont bf = BaseFont.createFont("C:/WINDOWS/Fonts/SIMSUN.TTC,1", BaseFont.IDENTITY_H, BaseFont.EMBEDDED); form.addSubstitutionFont(bf); // 6查询数据 Map<String, Object> data = new HashMap<String, Object>(); data.put("xh", "1021229"); data.put("xm", "徐小筱"); // 7遍历data 给pdf表单表格赋值 for (String key : data.keySet()) { form.setFieldProperty(key, "textfont", bf, null);// 设置字体 form.setField(key, data.get(key).toString()); } // 如果为false那么生成的PDF文件还能编辑,一定要设为true ps.setFormFlattening(true); //添加图片: 通过域名获取所在页和坐标,左下角为起点 int pageNo = form.getFieldPositions("zp").get(0).page; Rectangle signRect = form.getFieldPositions("zp").get(0).position; float x = signRect.getLeft(); float y = signRect.getBottom(); // 读图片 String imgpath = PdfController.class.getResource("/pdf/") + "zhaopian.jpg"; Image image = Image.getInstance(imgpath); // 获取操作的页面 PdfContentByte under = ps.getOverContent(pageNo); // 根据域的大小缩放图片 image.scaleToFit(signRect.getWidth(), signRect.getHeight()); // 添加图片 image.setAbsolutePosition(x, y); under.addImage(image); System.out.println("===============PDF导出成功============="); } catch (Exception e) { System.out.println("===============PDF导出失败============="); e.printStackTrace(); } finally { try { ps.close(); reader.close(); os.close(); } catch (Exception e) { e.printStackTrace(); } } return null; } }
第五步、jsp文件映射到Controller层
只要点击下载,文件就自动下载了
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <html> <body> <form action="exportpdf"> <input type="submit" value="下载"> </form> </body> </html>
最终结果:完美!
在开发过程中,需要将数据库中的数据以excel表格的方式导出。
首先说明。我这里用的是Apache的POI项目,它是目前比较成熟的HSSF接口,用来处理Excel对象。其实POI不仅仅只能处理excel,它还可以处理word、PowerPoint、Visio、甚至Outlook。
一.首先介绍利用POI如何生成excel。
首先在生成Excel前,我们需要理解一下Excel文件的组织形式。在POI中,是这样理解的:一个Excel文件对应一个workbook,一个workerbook是有若干个sheet组成的。一个sheet有多个row,一个row一般存在多个cell。
对于上面的四个名词我们可以在下图理解:
对于生成Excel,POI提供了如下几个基本对象:
HSSFWorkbook excel 的文档对象
HSSFSheet excel 的表单
HSSFRow excel 的行
HSSFCell excel 的格子单元
从上面的图片和Excel的组织结构,我们就可以明白创建Excel的步骤。
1、生成文档对象HSSHWorkbook。
2、通过HSSFWorkbook生成表单HSSFSheet。
3、通过HSSFSheet生成行HSSFRow
4、通过HSSFRow生成单元格HSSFCell。
下面展示代码:
第一步、导入jar包
<dependency> <groupId>org.apache.poi</groupId> <artifactId>poi-ooxml</artifactId> <version>3.9</version> </dependency>
第二步,创建Model对象
public class Person { private String id; private String name; private String password; private String age; public Person(String id, String name, String password, String age) { super(); this.id = id; this.name = name; this.password = password; this.age = age; } //提供set和get方法 }
第三步.下载界面 exportexcel.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <html> <!-- 正常数据导出肯定要传入参数,我这里没有用ajax传参,简单用链接传参 --> <script type="text/javascript"> function download(){ var url="download_excel?id=10&name=张三"; window.open(url); } </script> <body> <form action=""> <input type="button" value="报表导出" onclick="download()"/> </form> </body> </html>
第四步、ExcleController.java
import java.io.UnsupportedEncodingException; import java.net.URLEncoder; import javax.servlet.ServletOutputStream; import javax.servlet.http.HttpServletResponse; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; import com.ssm.service.impl.ExcleImpl; @Controller public class ExcleController { //这里直接new了 ExcleImpl excleImpl=new ExcleImpl(); @RequestMapping(value="/jsp/download_excel") //获取url链接上的参数 public @ResponseBody String dowm(HttpServletResponse response,@RequestParam("id") String id,@RequestParam("name") String name){ response.setContentType("application/binary;charset=UTF-8"); try{ ServletOutputStream out=response.getOutputStream(); try { //设置文件头:最后一个参数是设置下载文件名(这里我们叫:张三.pdf) response.setHeader("Content-Disposition", "attachment;fileName=" + URLEncoder.encode(name+".xls", "UTF-8")); } catch (UnsupportedEncodingException e1) { e1.printStackTrace(); } String[] titles = { "用户id", "用户姓名", "用户密码", "用户年龄" }; excleImpl.export(titles, out); return "success"; } catch(Exception e){ e.printStackTrace(); return "导出信息失败"; } } }
第五步、ExcleImpl 报表导出实现层
import java.util.ArrayList; import javax.servlet.ServletOutputStream; import org.apache.poi.hssf.usermodel.HSSFCell; import org.apache.poi.hssf.usermodel.HSSFCellStyle; import org.apache.poi.hssf.usermodel.HSSFRow; import org.apache.poi.hssf.usermodel.HSSFSheet; import org.apache.poi.hssf.usermodel.HSSFWorkbook; import com.ssm.model.Person; public class ExcleImpl { public void export(String[] titles, ServletOutputStream out) throws Exception{ try{ // 第一步,创建一个workbook,对应一个Excel文件 HSSFWorkbook workbook = new HSSFWorkbook(); // 第二步,在webbook中添加一个sheet,对应Excel文件中的sheet HSSFSheet hssfSheet = workbook.createSheet("sheet1"); // 第三步,在sheet中添加表头第0行,注意老版本poi对Excel的行数列数有限制short HSSFRow row = hssfSheet.createRow(0); // 第四步,创建单元格,并设置值表头 设置表头居中 HSSFCellStyle hssfCellStyle = workbook.createCellStyle(); //居中样式 hssfCellStyle.setAlignment(HSSFCellStyle.ALIGN_CENTER); HSSFCell hssfCell = null; for (int i = 0; i < titles.length; i++) { hssfCell = row.createCell(i);//列索引从0开始 hssfCell.setCellValue(titles[i]);//列名1 hssfCell.setCellStyle(hssfCellStyle);//列居中显示 } // 第五步,写入实体数据 Person person1=new Person("1","张三","123","26"); Person person2=new Person("2","李四","123","18"); Person person3=new Person("3","王五","123","77"); Person person4=new Person("4","徐小筱","123","1"); //这里我把list当做数据库啦 ArrayList<Person> list=new ArrayList<Person>(); list.add(person1); list.add(person2); list.add(person3); list.add(person4); for (int i = 0; i < list.size(); i++) { row = hssfSheet.createRow(i+1); Person person = list.get(i); // 第六步,创建单元格,并设置值 String id = null; if(person.getId() != null){ id = person.getId(); } row.createCell(0).setCellValue(id); String name = ""; if(person.getName() != null){ name = person.getName(); } row.createCell(1).setCellValue(name); String password = ""; if(person.getPassword() != null){ password = person.getPassword(); } row.createCell(2).setCellValue(password); String age=null; if(person.getAge() !=null){ age = person.getAge(); } row.createCell(3).setCellValue(age); } // 第七步,将文件输出到客户端浏览器 try { workbook.write(out); out.flush(); out.close(); } catch (Exception e) { e.printStackTrace(); } }catch(Exception e){ e.printStackTrace(); throw new Exception("导出信息失败!"); } } }
第六步:最终效果,当我点击报表导出按钮
完美!
导入excel文件数据到数据库
第一步、导入jar包
<dependency> <groupId>org.apache.poi</groupId> <artifactId>poi-ooxml</artifactId> <version>3.9</version> </dependency>
第二步,创建Model对象
我没有把数据放到数据库中,而是导入到实体中,然后在后台打印
public class Family { //家庭编号 private String jtbh; //姓名 private String xm; //行业 private String hy; //备注 private String bz; /* * 提供set和get,toString方法 */ }
第三步.导入excel界面 leadingexcel.jsp
<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%> <html> <head> <script type="text/javascript" src="../js/jquery-1.7.1.js"></script> <script type="text/javascript" src="../js/jquery.form.js"></script> <script type="text/javascript"> /* ajax 方式上传文件操作 */ $(document).ready(function(){ $("#btn").click(function(){ if(checkData()){ $('#form1').ajaxSubmit({ url:'uploadExcel/ajax', dataType: 'text', success: resutlMsg, error: errorMsg }); function resutlMsg(msg){ alert(msg); $("#upfile").val(""); } function errorMsg(){ alert("导入excel出错!"); } } }); }); //JS校验form表单信息 function checkData(){ var fileDir = $("#upfile").val(); var suffix = fileDir.substr(fileDir.lastIndexOf(".")); if("" == fileDir){ alert("选择需要导入的Excel文件!"); return false; } if(".xls" != suffix && ".xlsx" != suffix ){ alert("选择Excel格式的文件导入!"); return false; } return true; } </script> </head> <body> <form method="POST" enctype="multipart/form-data" id="form1" action="uploadExcel/form"> <label>上传文件: </label> <input id="upfile" type="file" name="upfile"><br> <br> <input type="submit" value="表单提交" onclick="return checkData()"> <input type="button" value="ajax提交" id="btn" name="btn" > </form> </body> </html>
先讲下,我这src引用路径的时候发现,怎么也引用不到,找了好久才发现,我在springmvc中没有配置静态文件
springmvc.xml
<!-- 静态资源访问 --> <mvc:default-servlet-handler/> <!-- 当我仅配置上面的时候又发现src是引用到了,但是我的RequestMapping映射却变成请求不到了,所以下面的也一定要加上 --> <mvc:annotation-driven></mvc:annotation-driven>
第四步、LeadingExcelController.java
import java.io.InputStream; import java.io.PrintWriter; import java.util.List; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartHttpServletRequest; import com.ssm.model.Family; import com.ssm.service.impl.ImportExcelUtil; @Controller @RequestMapping("/jsp/uploadExcel") public class LeadingExcelController { @RequestMapping("/form") public String form(HttpServletRequest request)throws Exception{ MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request; InputStream in =null; List<List<Object>> listob = null; MultipartFile file = multipartRequest.getFile("upfile"); if(file.isEmpty()){ throw new Exception("文件不存在!"); } in = file.getInputStream(); listob = new ImportExcelUtil().getBankListByExcel(in,file.getOriginalFilename()); in.close(); //该处可调用service相应方法进行数据保存到数据库中,现只对数据输出 for (int i = 0; i < listob.size(); i++) { List<Object> lo = listob.get(i); Family family = new Family(); family.setJtbh(String.valueOf(lo.get(0))); family.setXm(String.valueOf(lo.get(1))); family.setHy(String.valueOf(lo.get(2))); family.setBz(String.valueOf(lo.get(3))); System.out.println("打印信息-->"+family.toString()); } return null; } @RequestMapping(value="/ajax") public void ajaxUploadExcel(HttpServletRequest request,HttpServletResponse response) throws Exception { MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request; InputStream in =null; List<List<Object>> listob = null; MultipartFile file = multipartRequest.getFile("upfile"); if(file.isEmpty()){ throw new Exception("文件不存在!"); } in = file.getInputStream(); listob = new ImportExcelUtil().getBankListByExcel(in,file.getOriginalFilename()); //该处可调用service相应方法进行数据保存到数据库中,现只对数据输出 for (int i = 0; i < listob.size(); i++) { List<Object> lo = listob.get(i); Family family = new Family(); family.setJtbh(String.valueOf(lo.get(0))); family.setXm(String.valueOf(lo.get(1))); family.setHy(String.valueOf(lo.get(2))); family.setBz(String.valueOf(lo.get(3))); System.out.println("打印信息-->"+family.toString()); } PrintWriter out = null; response.setCharacterEncoding("utf-8"); //防止ajax接受到的中文信息乱码 out = response.getWriter(); out.print("文件导入成功!"); out.flush(); out.close(); } }
第五步、ImportExcelUtil.java 报表导入实现层
import java.io.IOException; import java.io.InputStream; import java.text.DecimalFormat; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.List; import org.apache.poi.hssf.usermodel.HSSFWorkbook; import org.apache.poi.ss.usermodel.Cell; import org.apache.poi.ss.usermodel.Row; import org.apache.poi.ss.usermodel.Sheet; import org.apache.poi.ss.usermodel.Workbook; import org.apache.poi.xssf.usermodel.XSSFWorkbook; public class ImportExcelUtil { private final static String excel2003L =".xls"; //2003- 版本的excel private final static String excel2007U =".xlsx"; //2007+ 版本的excel /** * 描述:获取IO流中的数据,组装成List<List<Object>>对象 * @param in,fileName * @return * @throws IOException */ public List<List<Object>> getBankListByExcel(InputStream in,String fileName) throws Exception{ List<List<Object>> list = null; //创建Excel工作薄 Workbook work = this.getWorkbook(in,fileName); if(null == work){ throw new Exception("创建Excel工作薄为空!"); } Sheet sheet = null; Row row = null; Cell cell = null; list = new ArrayList<List<Object>>(); //遍历Excel中所有的sheet for (int i = 0; i < work.getNumberOfSheets(); i++) { sheet = work.getSheetAt(i); if(sheet==null){continue;} //遍历当前sheet中的所有行 for (int j = sheet.getFirstRowNum(); j < sheet.getLastRowNum(); j++) { row = sheet.getRow(j); if(row==null||row.getFirstCellNum()==j){continue;} //遍历所有的列 List<Object> li = new ArrayList<Object>(); for (int y = row.getFirstCellNum(); y < row.getLastCellNum(); y++) { cell = row.getCell(y); li.add(this.getCellValue(cell)); } list.add(li); } } in.close(); return list; } /** * 描述:根据文件后缀,自适应上传文件的版本 * @param inStr,fileName * @return * @throws Exception */ public Workbook getWorkbook(InputStream inStr,String fileName) throws Exception{ Workbook wb = null; String fileType = fileName.substring(fileName.lastIndexOf(".")); if(excel2003L.equals(fileType)){ wb = new HSSFWorkbook(inStr); //2003- }else if(excel2007U.equals(fileType)){ wb = new XSSFWorkbook(inStr); //2007+ }else{ throw new Exception("解析的文件格式有误!"); } return wb; } /** * 描述:对表格中数值进行格式化 * @param cell * @return */ public Object getCellValue(Cell cell){ Object value = null; DecimalFormat df = new DecimalFormat("0"); //格式化number String字符 SimpleDateFormat sdf = new SimpleDateFormat("yyy-MM-dd"); //日期格式化 DecimalFormat df2 = new DecimalFormat("0.00"); //格式化数字 switch (cell.getCellType()) { case Cell.CELL_TYPE_STRING: value = cell.getRichStringCellValue().getString(); break; case Cell.CELL_TYPE_NUMERIC: if("General".equals(cell.getCellStyle().getDataFormatString())){ value = df.format(cell.getNumericCellValue()); }else if("m/d/yy".equals(cell.getCellStyle().getDataFormatString())){ value = sdf.format(cell.getDateCellValue()); }else{ value = df2.format(cell.getNumericCellValue()); } break; case Cell.CELL_TYPE_BOOLEAN: value = cell.getBooleanCellValue(); break; case Cell.CELL_TYPE_BLANK: value = ""; break; default: break; } return value; } }
第六步:最终效果,当我点击通过表单和ajax提交时
(1)先展示上传的xls文件内容
(2)最终控制台打出:
(3)通过ajax导入成功,前端也会提示
完美!
模型数据类型
SpringMVC 提供了以下几种途径输出模型数据:
– ModelAndView: 处理方法返回值类型为 ModelAndView时, 方法体即可通过该对象添加模型数据
– Map及Model:入参为org.springframework.ui.Model、org.springframework.ui.ModelMap 或 Java.uti.Map 时,处理方法返回时,Map中的数据会自动添加到模型中。
– @SessionAttributes: 将模型中的某个属性暂存到HttpSession 中,以便多个请求之间可以共享这个属性
– @ModelAttribute: 方法入参标注该注解后, 入参的对象就会放到数据模型中。
一.ModelAndView
目标方法的返回值可以是ModelAndView类型,其中可以包含视图和模型信息
springmvc会把ModelAndView的model中数据放在request域对象中
@RequestMapping("/springmvc") @Controller public class SpringMVCTest { private static final String SUCCESS = "success"; /** * 目标方法的返回值可以是ModelAndView类型 * 其中可以包含视图和模型信息 * springmvc会把ModelAndView的model中数据放在request域对象中 * @return*/ @RequestMapping("/testModelAndView") public ModelAndView testModelAndView(){ String viewName=SUCCESS; //添加模型视图 ModelAndView modelAndView=new ModelAndView(viewName); //添加模型数据到ModelAndView中 modelAndView.addObject("time", new Date()); return modelAndView; }
index.jsp
<a href="springmvc/testModelAndView">Test ModelAndView<a>
success.jsp
<html> <h4>Success Page</h4> time:${requestScope.time} </html>
二.Map 及 Model
入参为org.springframework.ui.Model、org.springframework.ui.ModelMap 或 java.uti.Map 时,处理方法返回时,Map 中的数据会自动添加到模型中
Controller类
@RequestMapping("/testMap") public String testMap(Map<String, Object> map) { map.put("names", Arrays.asList("tom", "jerry", "mike")); return "success";
index.jsp
<a href="springmvc/testMap">Test Map</a>
success.jsp
map: ${requestScope.names }
界面
三.@SessionAttributes
如果希望在多个请求之间共用某个模型属性数据,则可以在控制器类标注一个 @SessionAttributes,SpringMVC 会将模型中对应的属性暂存到 HTTPSession 中。
@SessionAttributes 除了可以通过属性名指定需要放到会话中的属性外,还可以通过模型属性的对象类型指定哪些模型属性需要放到会话中。
1. @SessionAttributes(types=User.class)会将隐含模型中所有类型为 User 的属性添加到会话中
2. @SessionAttributes(value={"user1", "user2"})将名为 user1 和 user2 的模型属性添加到会话中
3. @SessionAttributes(types={"User.class", "Dept.class"})将模型中所有类型为 User 及 Dept 的属性添加到会话中
4. @SessionAtributes(value={"user1", "user2"}, types={Dept.class})将名为 user1 和 user2 的模型属性添加到会话中,同时将所有类型为 Dept 的模型属性添加到会话中
controller类
//SessionAttributes只能放在类上,不能在方法上 @SessionAttributes(value={"user"}, types={String.class}) @RequestMapping("/springmvc") @Controller public class SessionController { private static final String SUCCESS = "success"; @RequestMapping("/testSessionAttributes") public String testSessionAttributes(Map<String, Object> map) { User user = new User("Jack", "123"); map.put("user", user); map.put("msg", "hello"); return SUCCESS; } }
index.jsp
<a href="springmvc/testSessionAttributes">Test SessionAttributes</a>
success.jsp
request user: ${requestScope.user } request msg: ${requestScope.msg } session user: ${sessionScope.user } session msg: ${sessionScope.msg }
最终request和session都有相应值,由此我们可以得出:
被 @SessionAttributes 注解修饰后,模型属性不仅存在于请求域还存在于会话域。除了可以通过value属性值指定需要放到会话中的属性外,还可以根据types属性值指定哪些类型的模型属性需要放到会话中。
四.@ModelAttribute
@ModelAttribute注解只支持一个属性value,类型是为String,代表绑定的属性名称。
@ModelAttribute会优先于@RequestMapping执行,也会在Controller中每个方法执行前被执行,所以当一个Controller中有映射到多个Url时,需要谨慎使用
(1)先讲下基本理解,网上讲的无非就那么几种:
@ModelAttribute public void myModel3(Model model) { model.addAttribute("name", "SHANHY"); model.addAttribute("age", "28"); } /** * 这个相当于 model.addAttribute("name", name); */ @ModelAttribute("name") public String userModelfirst(@RequestParam("name") String name){ return name; } /** * 这个相当于 model.addAttribute("string", name); * 因为你自己没有设置model的key值,所以它会默认value的类型第一个字母小写作为key值 * 如果你是User对象,那它会默认key值为"user",这个在实际开发中并不适用 * 因为太局限了,我们很难接受 key 为 string、int、user 等等这样的。 */ @ModelAttribute public String myModel1(@RequestParam(required = false) String name) { return name; }
(2)RequestMapping方法中取ModelAttribute方法中的值
modelattr.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <html> <body> <!-- 这里我输入用户名:李四 密码:5678 --> <form action="modelattr/test1"> <label>用户名:</label> <input type="text" id="name" name="name"></input><br><br> <label>密码:</label> <input type="text" id="pwd" name="pwd"></input><br><br> <input type="submit" value="登录"/> </form> </body> </html>
ModelAttrController类
import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; @Controller @RequestMapping(value="/modelattr") public class ModelAttrController { @ModelAttribute public void Model1(Model model) { model.addAttribute("name", "张三"); model.addAttribute("pwd", "1234"); } /** * test1方法中,有两个值是通过Model1方法中放入的 * 有两个值是通过前端获取的我们看后台打印结果 */ @RequestMapping(value="/test1") public String test1( @ModelAttribute("name") String str2, @ModelAttribute("pwd") String str3, @RequestParam("name") String name, @RequestParam("pwd") String pwd) { System.out.println("name="+str2+",pwd="+str3); System.out.println("name="+name+",pwd="+pwd); return null; } }
后台打印结果:
(3)有关更新,具体看案例
modelPerson.jsp
<html> <body> <!-- 模拟修改操作 1. 原始数据为: 1, zhangsan, 123456,12 2. 密码不能被修改. 3. 表单回显, 模拟操作直接在表单填写对应的属性值 --> <form action="modelattr/person" method="Post"> <input type="hidden" name="id" value="1"/> name: <input type="text" name="name" value="zhangsan"/> <br> age: <input type="text" name="age" value="12"/> <br> <input type="submit" value="Submit"/> </form> </body> </html>
ModelAttrController类
import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; import com.ssm.model.Person; @Controller @RequestMapping(value="/modelattr") public class ModelAttrController { /** *1: 因为password我在界面上是没有输入的,所以我通过id去数据库找到这条数据,就能获得它的password *2:Person领域对象就id name password age 四个属性都是String形 */ @ModelAttribute public void getUser(@RequestParam(value="id",required=false) String id, Map<String, Object> map){ if(id != null){ //模拟从数据库中获取对象 Person person = new Person("1", "lisi", "123456", "24"); System.out.println("从数据库中获取一个对象: " + person); map.put("person", person); } } @RequestMapping(value="/person", method=RequestMethod.POST) public String testModelAttribute(Person person){ System.out.println("修改: " + person); return null; } /* * 总结几点: * 1:map.put("person", person);中的key值,一定要和Person person中的形参一致,否则报错 * 2:如果去掉@ModelAttribute注解和getUser方法,直接testModelAttribute(Person person)会报错 * java.lang.NoSuchMethodException: com.ssm.model.Person.<init>() * 3:最后修改的那个person其实就是从数据库中和前端界面传来的集合体,就是说如果前端有值那就覆盖数据库中对于 * 属性的值,如果前段没有值那就还是用数据库中属性的值 */ }
后台打印结果
(4)@ModelAttribute和@RequestMapping同时注释的有返回值的方法
import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; @Controller @RequestMapping(value="/modelattr") public class ModelAttrController { @ModelAttribute(value="username") @RequestMapping("/person") public String login(@RequestParam("name") String name){ return name; } /** * 这种情况比较有意思:以前return name;都是作为返回路径 * 现在它变成了value值 * model.addAttribute("username", name); * 那它的映射还是@RequestMapping中的value值这里指:modelattr/person * 我之前路径为:http://localhost:8080/ssm/modelattr/person * 那么返回路径为:http://localhost:8080/ssm/WEB-INF/jsp/modelattr/person.jsp */ }
先看WEB-INF/jsp/modelattr/person.jsp
内容
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <html> </head> <body> <h1>Person返回成功</h1> </body> </html>
最后我们看界面
有关处理模型数据就讲到这了,如果哪里讲的不周全也欢迎多多指教。
form标签作用
简单来讲form表单有两大作用
1:第一就是往后端提交数据或者前端回显数据时候,它会自动的绑定来自Model中的一个属性值到当前form对应的实体对象。
2:第二是它支持我们在提交表单的时候使用除GET和POST之外的其他方法进行提交,包括DELETE和PUT等。
接下来用案例来说话,看了很多博客,基本上都是用同一个实体来讲解,它确实很全面,我也用它来举例!
第一步:创建实体UserModel
public class UserModel{ private String username; private String password; private boolean testBoolean; private String[] selectArray; private String[] testArray; private Integer radioId; private Integer selectId; private List<Integer> selectIds; private Map<Integer,String> testMap; private String remark; /* * 提供set和get方法 */ }
第二步:FormController类
import java.util.Arrays; import java.util.HashMap; import java.util.Map; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.RequestMapping; import com.ssm.model.UserModel; @Controller public class FormController { @RequestMapping("/form") public String test(Model model){ if(!model.containsAttribute("userModel")){ UserModel userModel=new UserModel(); userModel.setUsername("小小"); userModel.setPassword("123456"); userModel.setTestBoolean(true); userModel.setSelectArray(new String[] {"唱歌"}); userModel.setTestArray(new String[] {"唱歌","跳舞","画画"}); userModel.setRadioId(1); userModel.setSelectId(2); userModel.setSelectIds(Arrays.asList(1,2)); Map<Integer,String> mapone=new HashMap<Integer,String>(); mapone.put(1, "唱歌"); mapone.put(2, "跳舞"); mapone.put(3, "画画"); userModel.setTestMap(mapone); userModel.setRemark("备注:我今年1岁了"); //将userModel数据放入 model.addAttribute("userModel", userModel); } return "formTag"; } }
第三步:formTag.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %> <html> <head> <body> <form:form modelAttribute="userModel" method="post"> input 标签: <form:input path="username"/><br/> password 标签: <form:password path="password"/><br/> 绑定boolean的checkbox标签:<br/> <form:checkbox path="testBoolean"/><br/> 绑定Array的checkbox 标签:<br/> <form:checkbox path="testArray" value="唱歌"/>唱歌 <form:checkbox path="testArray" value="跳舞"/>跳舞 <form:checkbox path="testArray" value="画画"/>画画 <form:checkbox path="testArray" value="武术"/>武术<br/> 绑定Array的checkboxs标签:<br/> <form:checkboxes path="selectArray" items="${userModel.testArray}"/><br/> 绑定Map的checkboxs 标签:<br/> <form:checkboxes path="selectIds" items="${userModel.testMap}"/><br/> 绑定Integer的radio 标签:<br/> <form:radiobutton path="radioId" value="0"/>0 <form:radiobutton path="radioId" value="1"/>1 <form:radiobutton path="radioId" value="2"/>2<br/> 绑定Map的radiobuttons 标签:<br/> <form:radiobuttons path="selectId" items="${userModel.testMap}"/><br/> 绑定Map的select 标签:<br/> <form:select path="selectId" items="${userModel.testMap}"/><br/> 不绑定items数据直接在form:option添加的select 标签:<br/> <form:select path="selectId"> <option>请选择人员</option> <form:option value="1">小</form:option> <form:option value="2">中</form:option> <form:option value="3">大</form:option> </form:select><br/> 不绑定items数据直接在html的option添加的select 标签:<br/> <form:select path="selectId"> <option>请选择人员</option> <option value="1">小</option> <option value="2">中</option> <option value="3">大</option> </form:select><br/> 用form:option绑定items的select 标签:<br/> <form:select path="selectId"> <option/>请选择人员 <form:options items="${userModel.testMap}"/> </form:select><br/> textarea 标签: <form:textarea path="remark"/><br/> <input type="submit" value="Submit" /> </form:form> </body> </html>
第四步:界面效果
第五步:细讲表单标签
(1)要使用Spring MVC提供的表单标签,首先需要在视图页面添加
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
2.form标签:
<form:form modelAttribute="userModel" method="post">
modelAttribute属性指定该form绑定的是哪个Model,当指定了对应的Model后就可以在form标签内部其它表单标签上通过为path指定Model属性的名称来绑定Model中的数据这里面需要注意userModel这个实体一定
要已经存在的,不然会报错,就比方说你一开始就加载这个页面,那model还没有把userModel放进来,那么这个页面就会报找不到userModel的错。
3.input标签:
<form:input path="username"/>
会生成一个type为text的Html input标签,通过path属性来指定要绑定的Model中的值。
4.password标签:
<form:password path="password"/>
会生成一个type为password的Html input标签,通过path属性来指定要绑定的Model中的值。
5.checkbox标签:
会生成一个type为checkbox的Html input标签,支持绑定boolean、数组、List或Set类型的数据。
绑定boolean数据会生成一个复选框,当boolean为true该复选框为选定状态,false为不选定状态。
<form:checkbox path="testBoolean"/>
绑定数组、List或Set类型的数据(以数组作为演示)如果绑定的数据中有对应checkbox指定的value时则为选定状态,反之为不选定状态:
<!-- 在testArray只有:唱歌,跳舞, 画画 --> 绑定Array的checkbox 标签:<br/> <form:checkbox path="testArray" value="唱歌"/>唱歌 <form:checkbox path="testArray" value="跳舞"/>跳舞 <form:checkbox path="testArray" value="画画"/>画画 <form:checkbox path="testArray" value="武术"/>武术<br/>
6.checkboxs标签:
会根据绑定的items数据生成一组对应的type为checkbox的Html input标签,绑定的数据可以是数组、集合或Map,其中checkboxs的path属性也必指定,当path中的数据有和items中的数据值同的时候对应的checkbox为选定状态,反之为不选定状态。
绑定集合数据(以数组作为演示)
<!-- 在selectArray数组中,我只放了:唱歌。 而在testArray数组中有:唱歌,跳舞, 画画 --> 绑定Array的checkboxs标签:<br/> <form:checkboxes path="selectArray" items="${userModel.testArray}"/><br/>
这里需要注意的是当使用EL表达式绑定时需要连Model的名称一起指定如${userModel.testArray}而不能像path一样只指定Model对应的属性名称。
但通常情况下我们需要的是checkbox显示的是名称,但选择后提交的是对应名称的值,比如id,我们就可以通过绑定Map来实现这个功能:
<!-- selectIds我放的是list集合元素有:1,2 testMap放有(1, "唱歌")(2, "跳舞")(3, "画画") --> 绑定Map的checkboxs 标签:<br/> <form:checkboxes path="selectIds" items="${userModel.testMap}"/><br/>
生成的一组checkbox中其中一个checkbox的html代码:
7.radiobutton标签
会生成一个type为radio的Html input标签,如果绑定的数据的值对应radiobutton指定的value时则为选定状态,反之为不选定状态:
<!-- 在 radioId属性我放的数据是:1 --> 绑定Integer的radio 标签:<br/> <form:radiobutton path="radioId" value="0"/>0 <form:radiobutton path="radioId" value="1"/>1 <form:radiobutton path="radioId" value="2"/>2
8.radiobuttons标签:
会根据绑定的items数据生成一组对应的type为radio的Html input标签,绑定的items数据可以是数组、集合或Map,其中radiobuttons的path属性也必指定,当path的值和items中的某条数据值相同的时候对应的radio为选定状态,反之为不选定状态,用法和checkboxs很相似。但要注意的是:checkboxs的path绑定的是集合radiobuttons的path绑定的是单个值:
<!-- 这里selectId我放的数据是:2 testMap放有(1, "唱歌")(2, "跳舞")(3, "画画") --> 绑定Map的radiobuttons 标签: <form:radiobuttons path="selectId" items="${userModel.testMap}"/>
9.select标签:
会生成一个Html select标签,绑定的items数据可以是数组、集合或Map会根据items的内容生成select里面的option选项,当path的值和items中的某条数据值相同的时候对应的option为选定状态,反之为不选定状态,用法与radiobuttons很相似:
<!-- 这里selectId我放的数据是:2 testMap放有(1, "唱歌")(2, "跳舞")(3, "画画") --> 绑定Map的select 标签:<br/> <form:select path="selectId" items="${userModel.testMap}"/><br/>
上面的是根据指定的items自动生成的option选项,但我们也可以不指定items手动添加select的option选项:
<!-- 这里selectId我放的数据是:2 --> 不绑定items数据直接在form:option添加的select 标签:<br/> <form:select path="selectId"> <option>请选择人员</option> <form:option value="1">小</form:option> <form:option value="2">中</form:option> <form:option value="3">大</form:option> </form:select>
其中添加<option>请选择人员</option> 可以让在没有进行选择的情况下不指定任何默认值。
下面看一下form:option 与option的区别:
不绑定items数据直接在form:option添加的select 标签:<br/> <form:select path="selectId"> <option>请选择人员</option> <form:option value="1">小</form:option> <form:option value="2">中</form:option> <form:option value="3">大</form:option> </form:select><br/> 不绑定items数据直接在html的option添加的select 标签:<br/> <form:select path="selectId"> <option>请选择人员</option> <option value="1">小</option> <option value="2">中</option> <option value="3">大</option> </form:select><br/>
由截图的结果可以看出form:option 正确选择了path中指定的selectId而option没有,说明form:option有数据绑定功能option没有。
另外我们也可以不为select指定items,而把items指定到form:option 上这两种效果基本是一样的,一点区别就是为select指定items再在select里面添加option是不起作用的会被items生成的option覆盖掉,而把items指定到form:option 上则可以再在select里面添加option:
用form:option绑定items的select 标签:<br/> <form:select path="selectId"> <option/>请选择人员 <form:options items="${userModel.testMap}"/> </form:select>
10.textarea标签:
<!-- remark属性数据是:"备注:我今年1岁了" --> textarea 标签: <form:textarea path="remark"/>
11.hidden标签:
会生成一个type为hidden的Html input标签,通过path属性来指定要绑定的Model中的值。
这篇文章也就基本上是参考别人的文章,自己动手敲了一遍,也没什么难点。