springMVC-初识

三层结构

框架
表现层(web层): springMVC
业务层(service层): spring
持久层(dao层): MyBatis
表现层一般使用MVC设计模型
M:model模型 例如javaBean等
V:view视图 例如jsp、html等
C:Controller控制器 例如Servlet等

springMVC:基于java实现MVC设计模型的请求驱动类型的轻量级Web框架,属于springFrameWork的后续产品

springMVC和Struts2区别

相同:都是基于MVC模型编写、底层都离不开原始ServletAPI、处理请求机制都是一个核心控制器
不同

  • 1-springMVC入口是一个Servlet,struts2是Filter
  • 2-springMVC基于方法设计,struts2是基于类,stuts2每次会创建一个动作类,所以springMVC快些
  • 3-springMVC使用更简洁,同时支持JSR303,处理ajax请求更方便
  • 4-struts2的OGNL表达式使页面开发效率更高些,但执行效率没比JSTL提升,尤其struts2表单标签远没有html执行效率高

pringMVC入门程序

需求:index.jsp点击超链接转发到成功jsp页面
搭建开发环境

  • 1-导入jar包
  • 2-web.xml配置springMVC核心控制器
<servlet>
    <servlet-name>DispatcherServlet</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param><!--初始化加载springmvc配置文件-->
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:springmvc.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
    <servlet-name>DispatcherServlet</servlet-name>
    <url-pattern>/</url-pattern>
</servlet-mapping>
  • 3-创建springmvc配置文件并配置
<!-- 配置创建 spring 容器要扫描的包 -->
<context:component-scan base-package="cn.xiaoai"></context:component-scan>
<!-- 配置视图解析器 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    <property name="prefix" value="/"></property>
    <property name="suffix" value=".jsp"></property>
</bean>
<!--开启spr ingMVC框架注解的支持-->
<mvc:annotation-driven></mvc:annotation-driven>		

springMVC处理流程

​ 1-Request请求,然后进入DispatcherServlet
​ 2-DispatcherServlet(前端控制器)
​ --》Handler(处理映射器):返回控制类和对应方法
​ --》HandlerAdapter(处理适配器): 执行方法后并获得请求页面封装成视图模型返回
​ --》ViewResolver(视图解析器):解析视图模型并返回
​ 渲染视图并把模型数据填充到request域中
​ 3-DispatcherServlet最后response响应

@RequestMapping

注解属性:

属性说明
value等于path,表示方法映射路径valu="/hello"
path表示方法映射路径path="/hello"
method表示请求的方式 需要一个对象 可以传多个值{},通过RequestMethod.来获得对应方式method={RequestMethod.POST
请求为post,方法才执行
params请求必须携带的参数params={“username”} 请求必须携带username这个参数,方法才执行
params={“username=heihei”} 请求必须携带username这个参数并且值为heihei,方法才执行
heades=限制请求消息头的条件heades={“Accept”} 请求必须包含请求头Accept,方法才执行

请求参数的绑定:

1-直接在方法参数中定义与传递参数相同名称的参数,(底层通过反射获取方法参数绑定)

//方法:
@RequestMapping("/testParam")
public String testParam(String username,String password){
    System.out.println("----------testParam()执行了");
    System.out.println(username+"--"+password);
    return "success";
}

//视图页面:
<a href="paramCTL/testParam?username=xiaoai&&password=111111">请求参数的绑定</a>

2-绑定到JavaBean对象

  • 参数名称和bean对象的set方法去掉set首字母小写的名称一致
  • 当JavaBean对象引用另一个JavaBean对象,则传参的名称可以多层引用,如:JavaBean对象引用了User对象则可以使用user.xx属性等。
//方法:
@RequestMapping("/saveAccount")
public String saveAccount(Account account){
    System.out.println("----------saveAccount()执行了");
    System.out.println(account);
    return "success";
}
<!--视图页面:-->
<form action="/paramCTL/saveAccount" method="post">
    姓名:<input type="text" name="username" placeholder="姓名"><br/>
    密码:<input type="text" name="password" placeholder="密码"><br/>
    金额:<input type="text" name="money" placeholder="金额"><br/>
    用户姓名:<input type="text" name="user.uname" placeholder="用户姓名"><br/>
    用户年龄:<input type="text" name="user.age" placeholder="用户年龄"><br/>
    <input type="submit"  value="提交"><br/>
</form>

3-绑定到list或map

<form action="paramCTL/saveAccount" method="post">
    姓名:<input type="text" name="username" placeholder="姓名"><br/>
    密码:<input type="text" name="password" placeholder="密码"><br/>
    金额:<input type="text" name="money" placeholder="金额"><br/>
    list用户姓名:<input type="text" name="list[0].uname" placeholder="用户姓名"><br/>
    list用户年龄:<input type="text" name="list[0].age" placeholder="用户年龄"><br/>
    map用户姓名:<input type="text" name="map['one'].uname" placeholder="用户姓名"><br/>
    map用户年龄:<input type="text" name="map['one'].age" placeholder="用户年龄"><br/>
    <input type="submit"  value="提交"><br/>
</form>

springMVC中文乱码的解决:(过滤器)

  • web.xml中配置
<!--配置解决中文乱码的过滤器-->
<filter>
    <filter-name>characterEncodingFilter</filter-name>
    <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
    <init-param>
        <param-name>encoding</param-name>
        <param-value>UTF-8</param-value>
    </init-param>
</filter>
<filter-mapping>
    <filter-name>characterEncodingFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

自定义类型转换器

例如:当属性为date类型传入了一个参数字符串为2020-11-11不符合date类型格式时会报错。此时需要用自定义类型转换器来完成

  • 1-先写程序:需要实现Converter接口
public class StringToDateConverter implements Converter<String,Date>{
    /**
	*
	* @param source 传入的字符串
	* @return
	*/
    @Override
    public Date convert(String source) {
        //判断
        if (source == null){
            throw new RuntimeException("请传入数据");
        }
        DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
        try {
            //把字符串转换日期
            return df.parse(source);
        } catch (Exception e) {
            throw new RuntimeException("数据类型转换出现错误");
        }
    }
}
  • 2-springMVC.xml配置文件中配置自定义类型转换器(注册)
<!--配置自定义类型转换器-->
<bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
	<property name="converters" >
		<set><!--添加自定义的类型转换器-->
			<bean class="cn.xiaoai.utils.StringToDateConverter"></bean>
		</set>
	</property>
</bean>
  • 3-使转换器生效
<!--开启springMVC框架注解的支持-->
<mvc:annotation-driven conversion-service="conversionService"></mvc:annotation-driven>

在核心控制器中拿到servlet原生api

  • 直接在方法参数里获取即可
@RequestMapping("/testServlet")
public String testServlet(HttpServletRequest request, HttpServletResponse response){
	System.out.println("----------testServlet()执行了");
	System.out.println(request);
    HttpSession session = request.getSession();
    System.out.println(session);

    ServletContext servletContext = session.getServletContext();
    System.out.println(servletContext);

    System.out.println(response);
    return "success";
}

常用注解

@RequestParam

把请求中指定名称的参数给控制器中形参赋值

  • 属性value:请求参数名称
  • 属性required:请求参数中是否必须提供此参数。默认true,表示必须提供,不提供则报错。
//方法:
@RequestMapping("/testRequestParam")
public String testRequestParam(@RequestParam(value = "name") String username){
    System.out.println("----------testRequestParam()执行了");
    System.out.println(username);//输出:xioaai
    return "success";
}

//页面视图:
<a href="anno/testRequestParam?name=xiaoai">RequestParam</a>

【@RequestBody】

用于获取请求体内容。直接使用得到是key=value&key=value…结构的数据 get请求方式不适用

  • 属性required:是否必须有请求体。默认true,get请求报错,为false,get请求到null。
@RequestMapping("/testRequestBody")
public String testRequestBody(@RequestBody String body){
    System.out.println("----------testRequestBody()执行了");
    System.out.println(body);//输出:username=xxx&age=xxx。xxx为表单里对应的输入值
    return "success";
}
<!--页面视图:-->
<form action="anno/testRequestBody" method="post">
    用户姓名:<input type="text" name="username" placeholder="用户姓名"><br/>
    用户年龄:<input type="text" name="age" placeholder="用户年龄"><br/>
    <input type="submit"  value="提交"><br/>
</form>

【@RequestHeader】

用于获取请求消息头 注:实际开发中一般不怎么用

  • 属性value:指定消息头名称
  • 属性required:是否必须有此消息头
@RequestMapping("/testRequestHeader")
public String testRequestHeader(@RequestHeader(value = "Accept") String header){
    System.out.println("----------testRequestHeader()执行了");
    System.out.println(header);
    return "success";
}

【@PathVariable】

绑定url中的占位符。例如:请求url中 /delete/{id},这个{id}就是url占位符。

  • 属性vlue:用于指定url中占位符名称
  • 属性required:是否必须提供占位符。
@RequestMapping("/testPathVariable/{sid}")
public String testPathVariable(@PathVariable(name = "sid")String id){
    System.out.println("----------testPathVariable()执行了");
    System.out.println(id);//输出10
    return "success";
}

视图页面:
<a href="anno/testPathVariable/10">PathVariable</a>

【@CookieValue】

获取某个cookie的数据
属性value:指定cookie名称
属性required:是否必须有此cookie

public String testCookieValue(@CookieValue(value = "JSESSIONID") String cookieValue){
    System.out.println("----------testCookieValue()执行了");
    System.out.println(cookieValue);
    return "success";
}

【@ModelAttribute】

  • 属性value:用于获取数据的key。可是pojo的属性名称,也可是map结构的key。

放在方法上:表示当前方法会在控制器的方法执行之前先执行

@RequestMapping("/testModelAttribute")
public String testModelAttribute(User user){
    System.out.println("----------testCookieValue()执行了");
    System.out.println(user);//输出:user信息并且date带有数据
    return "success";
}

/**
*由于该方法先执行,直接返回数据即可
* @param uname
* @return
*/
@ModelAttribute
public User showUser(String uname){
    System.out.println("----------showUser()方法执行了。。");
    User user = new User();
    //通过用户查询数据库(模拟)
    user.setUname(uname);
    user.setAge(20);
    user.setDate(new Date());
    return user;
}

放在参数上:获取指定的数据给参数赋值

@RequestMapping("/testModelAttribute")
public String testModelAttribute(@ModelAttribute("abc") User user){
    System.out.println("----------testCookieValue()执行了");
    System.out.println(user);//输出:user信息并且date带有数据
    return "success";
}
/**
*把数据存入map,再从map取数据复制赋值给参数
* @param uname
* @return
*/
@ModelAttribute
public void showUser(String uname, Map<String,User> map){
    System.out.println("----------showUser()方法执行了。。");
    User user = new User();
    //通过用户查询数据库(模拟)
    user.setUname(uname);
    user.setAge(20);
    user.setDate(new Date());
    map.put("abc",user);
}
视图页面:
<form action="anno/testModelAttribute" method="post">
    用户姓名:<input type="text" name="uname" placeholder="用户姓名"><br/>
    用户年龄:<input type="text" name="age" placeholder="用户年龄"><br/>
    <input type="submit"  value="提交"><br/>
</form>

【@SessionAttribute】

用于多次执行控制器方法间的参数共享。只能作用于类上

  • 属性value:指定存入的属性名称
  • 属性type:指定存入数据的类型
@Controller
@RequestMapping("/anno")
@SessionAttributes(value = {"SessionAttribute-msg"}) //把SessionAttribute-msg=xiaoai存入到session域中
public class AnnoController {
    //存入信息
    @RequestMapping("/testSessionAttribute")
    public String testSessionAttribute(Model model){
        System.out.println("----------testSessionAttribute()执行了");
        model.addAttribute("SessionAttribute-msg","xioaai");
        return "success";
    }
    //获取信息
    @RequestMapping("/getSessionAttribute")
    public String getSessionAttribute(ModelMap modelMap){
        System.out.println("----------getSessionAttribute()执行了");
        String SessionAttribute_msg = (String) modelMap.get("SessionAttribute-msg");
        System.out.println(SessionAttribute_msg);
        return "success";
    }
    //删除信息
    @RequestMapping("/delSessionAttribute")
    public String delSessionAttribute(SessionStatus status){
        System.out.println("----------delSessionAttribute()执行了");
        status.setComplete();
        return "success";
    }
}

REST风格URL:

通过请求方式来判断执行那一个方法

  • 当请求路径和请求方法一致时:通过url占位符来判断
path = "/user" method="get"
findAll()

path = "/user/{id}" method="get"
findById()

localhost:8080/user/10 get  
直接带变量10访问即可 不用localhost:8080/user?id=10 get
@PathVariable注解即用来取占位符的值

restful优点:结构清晰、符合标准、易于理解、扩展方便

基于HiddentHttpMethodFilter过滤器

form表单只支持GET和POST请求,DELETE/PUT等并不支持,

  • spring3.0添加了过滤器HiddentHttpMethodFilter可将浏览器请求改为指定请求方式

  • 通过表单hidden隐藏标签,修改请求方式

  • 其他类如WebClient使用静态方法发送请求,也可模拟各种请求

响应之返回值

1-String字符串

方法执行并跳转到名称为返回值字符串页面 底层最终也会选择ModelAndView的方式跳转

@RequestMapping(value = "/testString")
public String testString(Model model){
    System.out.println("----------testString()执行了。。。");
    //模拟从数据库中查询出User对象
    User user = new User();
    user.setUsername("xiaoai");
    user.setPassword("123");
    user.setAge(21);
    //model对象存入数据
    model.addAttribute("user",user);
    return "success";
}

2-void

方法执行,然后再次请求路径

@RequestMapping(value = "/testVoid")
public void testVoid(Model model){
    System.out.println("----------testVoid()执行了。。。");
}

跳转1----可以在视图目录下创建最后一级目录为名称的视图
跳转2----请求转发

@RequestMapping(value = "/testVoid")
public void testVoid(HttpServletRequest request, 
                     HttpServletResponse response) throws Exception {
    System.out.println("----------testVoid()执行了。。。");
    //编写请求转发的语句  请求转发:一次请求,不用编写项目的名称
    //请求转发不再调用视图解析器,如果有多级目录要手动加上
    request.getRequestDispatcher("success.jsp").forward(request,response);
    return;
}

跳转3----重定向

@RequestMapping(value = "/testVoid")
public void testVoid(HttpServletRequest request, 
                     HttpServletResponse response) throws Exception {
    System.out.println("----------testVoid()执行了。。。");
    //重定向
    response.sendRedirect(request.getContextPath()+"/success.jsp");
    return;
}

跳转4----直接响应

@RequestMapping(value = "/testVoid")
public void testVoid(HttpServletRequest request, 
                     HttpServletResponse response) throws Exception {
    System.out.println("----------testVoid()执行了。。。");
    //直接进行响应
    //--设置中文乱码
    response.setCharacterEncoding("UTF-8");
    response.setContentType("text/html;charset=UTF-8");
    //--响应
    response.getWriter().print("你好。直接响应");
    return;
}

3-返回值为ModelAndView类型

@RequestMapping(value = "/testModelAndView")
public ModelAndView testModelAndView(){
    System.out.println("----------testModelAndView()执行了。。。");
    //创建ModelAndView对象
    ModelAndView mv = new ModelAndView();
    //模拟从数据库中查询出User对象
    User user = new User();
    user.setUsername("xiaoai");
    user.setPassword("123");
    user.setAge(21);
    //把user对象存储到mv中,底层也会把user存入到request对象域中
    mv.addObject("user",user);
    //跳转到那个页面可以设置
    mv.setViewName("success");
    return mv;
}

响应之使用forword和redirect

请求转发和重定向是用不了视图解析的,所以路径问题需要注意
1–forward

@RequestMapping(value = "/testForword")
public String testForword(){
    System.out.println("----------testForword()执行了。。。");
    return "forward:/susccess.jsp";//路径需要自己手动填写其准确路径
}

2–redirect

@RequestMapping(value = "/testRedirect")
public String testRedirect(){
    System.out.println("----------testRedirect()执行了。。。");
    return "redirect:/suscces.jsp";//通过关键字来重定向返回可以不加项目名,框架默认帮加 
}

响应json数据

过滤静态资源

  • 默认核心控制器过滤掉了静态资源,需要解决:在springMVC配置文件中配置静态资源不拦截
<!--前端控制器,哪些静态资源不拦截-->
<mvc:resources location="/css/" mapping="/css/**"/>  <!-- 样式 -->
<mvc:resources location="/images/" mapping="/images/**"/>  <!-- 图片 -->
<mvc:resources mapping="/js/" location="/js/**"></mvc:resources>

模拟ajax异步请求

$("#btn").click(function () {
    //发送ajax请求
    $.ajax({
        //编写json格式,设置属性和值
        url:"user/testAjax",
        contentType:"application/json;charset=UTF-8",
        data:'{"username":"xiaoai","password":"123","age":"21"}',
        dataType:"json",
        type:"post",
        success:function (data) {
            //data表示服务器响应的json数据,进行解析
            alert(data);
            alert(data.username);
            alert(data.password);
            alert(data.age);
        }
    });
});
//控制器方法
@RequestMapping(value = "/testAjax")
public @ResponseBody User testAjax(@RequestBody User user){
    System.out.println("----------testAjax()执行了。。。");
    //客户端发送ajax异步请求,传递的是json字符串,后端把json字符串封装到user对象中
    System.out.println(user);
    //做响应,模拟查询数据库
    user.setUsername("haha");
    user.setAge(31);
    //做响应
    return user;
}

springMVC提供的文件上传

1–文件上传回顾

  • a-form表单enctype(表单请求正文的类型)取值必须是multipart/form-data(默认为:application/x-www-form-urlencoded)
  • b-method属性必须为post
  • c-提供一个文件选择域( )

2–上传原理分析

  • a-form表单enctype取值不是默认,request.getParameter()失效。

  • b-enctype="application/x-www-form-urlencoded"时,form表单正文内容:key=value&key=value&…

  • c-enctype="multipart/form-data"时,form表单正文内容:每部分都是MIME类型描述的正文

    3--借助第三方组件实现文件上传-----------------------------7de1a433602ac   			分界符 
    Content-Disposition: form-data; name="userName"  		协议头 
    aaa              										协议的正文 
    -----------------------------7de1a433602ac 
    Content-Disposition: form-data; name="file"; 
    filename="C:\Users\zhy\Desktop\fileupload_demofile\b.txt" 
    Content-Type: text/plain         						协议的类型(MIME 类型) 
    
    bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb 
    -----------------------------7de1a433602ac-- 
    

3–借助第三方组件实现文件上传

使用 Commons-fileupload 组件实现文件上传,需要导入该组件相应的支撑 jar 包:
	Commons-fileupload
	commons-io。
commons-io 不属于文件上传组件的开发 jar 文件,
Commons-fileupload 组件从 1.1 版本开始,它工作时需要 commons-io 包的支持。 

传统方式文件上传

@RequestMapping(value = "/fileUpload1")
public String fileUpload1(HttpServletRequest request) throws Exception {
    System.out.println("----------fileUpload1()执行了。。。文件上传");
    //使用fileupload组件完成文件上传
    //1-文件上传位置
    String path = request.getSession().getServletContext().getRealPath("/uploads/");
    //2-判断该路径是否存在
    File file = new File(path);
    if (!file.exists()){
        file.mkdirs();
    }
    //3-解析request对象,获取上传文件项
    DiskFileItemFactory factory = new DiskFileItemFactory();
    ServletFileUpload upload = new ServletFileUpload(factory);
    //解析request
    List<FileItem> items = upload.parseRequest(request);//全是文件项
    //遍历
    for (FileItem item:items){
        //进行判断,当前item对象是否是上传文件项
        if (item.isFormField()){ //说明是普通表单项

        }else{ //说明是上传文件项
            //获取上传文件名称
            String fileName = item.getName();
            //把文件名称设置为唯一值
            String uuid = UUID.randomUUID().toString().replace("-", "");
            fileName = uuid+"_"+fileName;
            //完成文件上传
            item.write(new File(path,fileName));//写到某个路径下
            item.delete();
        }
    }
    return "success";
}

视图页面:

<form action="fileUploadCTRL/fileUpload1" method="post" enctype="multipart/form-data">
    选择文件:<input type="file" name="upload" ><br/>
    <input type="submit" value="上传"><br/>
</form>

springMVC方式文件上传

原理分析

  • 文件 --》request --》前端控制器 --》配置的文件解析器:解析request,获取上传文件项项返回 --》前端控制器带着上传文件项 --》
  • 请求方法:通过MultipartFile类上传

springMVC配置文件配置组件:

<!--配置文件上传解析器 id名称必须为:multipartResolver-->
<bean id="multipartResolver" 
      class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
    <property name="maxUploadSize" value="10485760"></property>
</bean>

控制器方法:

@RequestMapping(value = "/fileUpload2")
public String fileUpload2(HttpServletRequest request,MultipartFile upload) throws Exception {
    System.out.println("----------fileUpload2()执行了。。。文件上传");
    //1-文件上传位置
    String path = request.getSession().getServletContext().getRealPath("/uploads/");
    //2-判断该路径是否存在
    File file = new File(path);
    if (!file.exists()){
        file.mkdirs();
    }
    //获取上传文件名称
    String fileName = upload.getOriginalFilename();
    //把文件名称设置为唯一值
    String uuid = UUID.randomUUID().toString().replace("-", "");
    fileName = uuid+"_"+fileName;
    //完成文件上传
    upload.transferTo(new File(path,fileName));
    return "success";
}

视图页面:

<form action="fileUploadCTRL/fileUpload2" method="post" enctype="multipart/form-data">
    选择文件:<input type="file" name="upload" ><br/><%--方法参数名称必须和该name一致--%>
    <input type="submit" value="上传"><br/>
</form>

以前笔记记录的文件上传和下载

例子1(传统上传)

//半框架实现上传
@RequestMapping(value = "/up",method = RequestMethod.POST)
public String up(@RequestParam("uploadFile") MultipartFile uploadFile ,
                 String desc,
                 HttpSession session) throws IOException {
    //获取文件上传的名称
    String fileName = uploadFile.getOriginalFilename();
    String path = session.getServletContext().getRealPath("photo")+File.separator+fileName;
    //获取输入输出流
    InputStream is = uploadFile.getInputStream();
    OutputStream os = new FileOutputStream(new File(path));

    //    //一个一个字节上传
//		int i=0;
//		while ((i=is.read())!=-1) {
//			os.write(i);
//		}
    
    //字节数组上传
    int i=0;
    byte[] flush = new byte[1024];
    while ((i=is.read(flush))!=-1) {
        os.write(flush,0,i);
    }
    os.close();
    is.close();
    return "success";
}

例子2(框架直接上传)

//利用框架实现上传
@RequestMapping(value = "/up_old",method = RequestMethod.POST)
public String up_old(@RequestParam("uploadFile") MultipartFile uploadFile ,
                     String desc,
                     HttpSession session) throws IOException {
    //获取文件上传的名称
    String fileName = uploadFile.getOriginalFilename();
    String finalFileName = UUID.randomUUID()+fileName.substring(fileName.lastIndexOf("."));//解决重名问题
    String path = session.getServletContext().getRealPath("photo")+File.separator+finalFileName;
    File file = new File(path);
    uploadFile.transferTo(file);
    return "success";
}

例子(固定图片下载)

@RequestMapping(value = "/down")
public ResponseEntity<byte[]> down(HttpSession session ) throws IOException{
    //获取下载文件的路径
    String realPath = session.getServletContext().getRealPath("img");
    String finalPath = realPath + java.io.File.separator+"日向雏田.jpg";
    //读取要下载的文件
    InputStream is = new FileInputStream(finalPath);
    byte[] b = new byte[is.available()];//available()获取输入流所读取的文件的最大字节数
    is.read(b);
    //设置请求头
    HttpHeaders headers = new HttpHeaders();
    headers.add("Content-Disposition", "attachment;filename=zzz.jpg");
    //设置响应状态
    HttpStatus statusCode = HttpStatus.OK;
    ResponseEntity< byte[]> entity = new ResponseEntity<byte[]>(b, headers, statusCode);
    is.close();
	return entity;
}

springMVC跨服务器方式的文件上传

需要导入相应的jar包(该jar包由sun公司提供)

com.sun.jersey:jersey-client:1.18.1
com.sun.jersey:jersey-core:1.18.1
@RequestMapping(value = "/fileUpload3")
public String fileUpload3(MultipartFile upload) throws Exception {
    System.out.println("----------fileUpload3()执行了。。。跨服务器文件上传");
    //定义上传文件服务器路径
    String path = "http://localhost:9090/uploads/";
    //2-判断该路径是否存在
    File file = new File(path);
    if (!file.exists()){
        file.mkdirs();
    }
    //获取上传文件名称
    String fileName = upload.getOriginalFilename();
    //把文件名称设置为唯一值
    String uuid = UUID.randomUUID().toString().replace("-", "");
    fileName = uuid+"_"+fileName;
    //完成文件上传,跨服务器上传
    //创建客户端的对象
    Client client = Client.create();
    //和图片服务器进行连接
    WebResource webResource = client.resource(path + fileName);
    //上传文件
    webResource.put(upload.getBytes());
    return "success";
}

springMVC异常处理

产生的异常都是一层一层往上抛出的,不处理最后会抛出到浏览器。
异常处理器组件:不把异常抛出到浏览器,通过异常处理器处理异常(把友好错误提示页面响应到浏览器)

  • 1–编写自定义异常类(做提示信息)
public class SysException extends Exception{
    //存储提示信息的
    private String message;
    @Override
    public String getMessage() {
        return message;
    }
    public void setMessage(String message) {
        this.message = message;
    }
    public SysException(String message) {
        this.message = message;
    }
}

2–编写异常处理器(需要实现HandlerExceptionResolver接口)

public class SysExceptionResolver implements HandlerExceptionResolver{
    @Override
    public ModelAndView resolveException(
        HttpServletRequest httpServletRequest, 
        HttpServletResponse httpServletResponse, 
        Object o, 
        Exception ex) {
        //获取异常对象
        SysException e = null;
        if (ex instanceof SysException){
            e = (SysException) ex;
        }else{
            e = new SysException("系统正在维护....");
        }
        //创建modelAndView
        ModelAndView  mv = new ModelAndView();
        mv.addObject("errorMsg", e.getMessage());
        mv.setViewName("errorPage");
        return mv;
    }
}

3–配置异常处理器(跳转提示页面) springMVC配置文件配置

<!--配置异常处理器-->
<bean id="sysExceptionResolver" class="cn.xiaoai.exception.SysExceptionResolver"></bean>

4–控制器方法:

@RequestMapping(value = "/testException")
public String testException() throws SysException{
    System.out.println("----------testException()执行了。。。异常处理");
    try {
        //模拟异常
        int a = 10/0;
    } catch (Exception e) {
        //打印异常信息
        e.printStackTrace();
        //抛出自定义异常
        throw new SysException("服务器走丢了。。。。");
    }
    return "success";
}

​ 5–视图页面:

<h3>异常处理页面</h3>
<a href="user/testException">异常处理</a>
		

<h3>错误页面</h3>
${errorMsg}<%--打印错误信息--%>

springMVC拦截器

拦截器类似过滤器filter,可以一个或多个

  • 请求–》拦截器(执行放行前代码) --》controller --》拦截器(执行放行后代码)–》响应

拦截器和过滤器区别

  • 过滤器是servlet规范一部分,任何java web工程都能用,拦截器是springMVC框架自己的,只有springMVC框架才能用
  • 过滤器在url-pattern中配置/*后,所有访问的资源都拦截,拦截器只拦截访问的控制方法,访问的是jsp、html、css、image或js等不会进行拦截

自定义拦截器:

//编写拦截器类(需要实现HandlerInterceptor接口)
public class MyInterceptor1 implements HandlerInterceptor{
    /** 预处理,放行前执行的方法(controller方法执行前执行)   
    return false==不放行 
    true==放行 执行下一拦截器,
    没有则执行controller中方法*/
    @Override
    public boolean preHandle(HttpServletRequest request, 
                             HttpServletResponse response, 
                             Object handler) throws Exception {
        System.out.println("----------MyInterceptor1拦截器执行了。。。。放行之前的代码");
        return true;
    }
    //放行后执行的方法(controller方法执行后执行)
    @Override
    public void postHandle(HttpServletRequest request, 
                           HttpServletResponse response, 
                           Object handler, 
                           ModelAndView modelAndView) throws Exception {
        System.out.println("----------MyInterceptor1拦截器执行了。。。。放行之后的代码");
    }
    //最后执行的方法
    @Override
    public void afterCompletion(HttpServletRequest request, 
                                HttpServletResponse response, 
                                Object handler, Exception ex) throws Exception {
        System.out.println("----------MyInterceptor1拦截器执行了。。。。最后执行代码");
    }
}

配置拦截器(springMVC配置文件中配置)

<!--配置拦截器-->
<mvc:interceptors>
    <mvc:interceptor>
        <!--要拦截的具体的方法  /**==所有方法都拦截  /user/*==user路径下所有方法拦截-->
        <mvc:mapping path="/user/*"/>
        
		<!--不要拦截的方法-->
        <!--<mvc:exclude-mapping path=""></mvc:exclude-mapping>-->
       
        <!--配置拦截器对象-->
        <!--注册拦截器-->
        <bean id="myInterceptor1" class="cn.xiaoai.interceptor.MyInterceptor1"></bean>
    </mvc:interceptor>
</mvc:interceptors>

当两个拦截器时执行顺序如下:

----------MyInterceptor1拦截器执行了。。。。放行之前的代码
----------MyInterceptor2拦截器执行了。。。。放行之前的代码
----------testInterceptor()执行了。。。拦截器测试的控制器方法
----------MyInterceptor2拦截器执行了。。。。放行之后的代码
----------MyInterceptor1拦截器执行了。。。。放行之后的代码
----------success.jsp执行了。。。
----------MyInterceptor2拦截器执行了。。。。最后执行代码
----------MyInterceptor1拦截器执行了。。。。最后执行代码

ssm整合

表现层(web层):springMVC框架
业务层:spring框架
持久层:myBatis框架

一定是用spring框架去整合其他两个框架 写配置文件或注解?怎么简单怎么来 选:配置文件*注解方式

**整合步骤:**先配置每个框架,框架可以正常使用。再通过spring整合。

spring整合springMVC

思路:service交由spring管理,在控制器方法中可以注入service对象并调用其方法,方法正常使用即spring和springMVC整合成功

实现:在web.xml中加载了springMVC的配置文件,但spring配置文件还没有被加载,所以通过监听器把spring配置文件一起加载进来,把service交由spring管理,

<!--web.xml配置文件中配置监听器加载spring配置文件-->
<!--配置spring的监听器, 默认只加载WEB-INF目录下的applicationContext.xml文件-->
<listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!--设置配置文件的路径-->
<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath:applicationContext.xml</param-value>
</context-param>

spring整合myBatis

思路:在service层中可以注入dao层并调用其方法,dao层功能实现即spring和myBatis整合成功。
实现:在spring配置文件中配置使得spring的ioc容器中有相关dao接口代理对象

<!--spring整合myBatis。spring.xml配置文件中配置整合myBatis-->

<!--配置连接池-->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
    <property name="driverClass" value="com.mysql.jdbc.Driver"></property>
    <property name="jdbcUrl" value="jdbc:mysql:///ssm"></property>
    <property name="user" value="root"></property>
    <property name="password" value="root"></property>
</bean>

<!--配置sqlSessionFactory对象-->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
    <property name="dataSource" ref="dataSource"></property>
</bean>

<!--配置AccountDao接口所在的包-->
<bean id="mapperScanner" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
    <property name="basePackage" value="cn.xiaoai.dao"></property>
</bean>


<!--配置spring框架声明式事务管理-->
<!--配置事务管理-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource"></property>
</bean>

<!--配置事务通知-->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
    <tx:attributes>
        <tx:method name="find*" read-only="true"/>
        <tx:method name="*" isolation="DEFAULT"></tx:method>
    </tx:attributes>
</tx:advice>

<!--配置AOP增强-->
<aop:config>
    <aop:advisor advice-ref="txAdvice" 
                 pointcut="execution(* cn.xiaoai.service.impl.*ServiceImpl.*(..))">
    </aop:advisor>
</aop:config>

当myBatis的配置文件的配置已经通过spring配置完,则myBatis配置文件可删除。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值