1、在springmvc中,json数据里面的data参数里面必须用双引号,才能传到后台一json对象,然后才能被@RequestBody转成javabean对象,并且要在外面用单引号括起来(传json整个数据的时候)--在springmvc里面用的多------
如果不加单引号,传递过去的就是一个参数键值对,而不是一个完整的json对象
contentType:‘application/json;charset=utf-8‘,
data:‘{"name":"黑妹牙膏","price":"999"}‘,
2、传参数的时候,data参数是一个对象,{},外面如果加双引号或者单引号,会得不到数据(struts2)
一、内容回顾:
线程安全概念:
线程安全:多次访问同一个对象/变量,得到同一个结果
线程不安全:多次访问同一个对象/变量,得到不同结果
1、springmvc是否线程安全
安全,springmvc底层是servlet,是单例
2、i++,++i是否线程安全
成员变量:线程不安全
public class A{
int i=9;
i++;
}
3、有了struts2,为什么还需要使用springmvc?
①、底层实现机制:struts2:过滤器 springmvc:servlet
②、运行效率:struts2 :多例运行 很耗资源 springmvc:单例,比struts快
③、参数封装:struts2:基于属性进行封装 springmvc:基于方法进行封装---方法参数是局部变量,方法执行结束,方法变量内存释放。
二、springmvc相关注解
1、@RequestMapping注解的几种使用
* 1,@RequestMapping("itemsList")
* 2,@RequestMapping("/itemsList")
* 3,@RequestMapping("itemsList.do") --前提是web.xml里面配置的路径为 *.do
* 4,@RequestMapping(value="itemsList")
* 5,@RequestMapping(value="itemsList",method=RequestMethod.POST)
* 6,@RequestMapping(value="itemsList",method=RequestMethod.GET)
* 7,@RequestMapping(value="itemsList",method={RequestMethod.GET,RequestMethod.POST})
(href,直接通过浏览器发送都是get请求;form表单,ajax指定post,都是post)
2、@RequestParam注解:
* 功能:
* 1,设置默认值(如果页面传递值为null,自动设置为默认值) @RequestParam(defaultValue="2")
* 2,设置别名 (如果页面传递参数名称和方法接受参数名称不一致,设置别名) @RequestParam(value="ids")
* 同时设置:
* @RequestParam(defaultValue="2",value="ids")
3、商品更新
/**
* 需求:根据id更新商品数据
* 请求:/item/updateSubmit
* 参数:item
* 返回值:重定向商品列表
*/
@RequestMapping("/item/updateSubmit")
public String updateSubmit(Item item){
itemService.updateItemByID(item);
return "redirect:/itemsList.do";
}
<!-- 商品更新 -->
<update id="updateItemByID" parameterType="item" >
update items set name=#{name},price=#{price},detail=#{detail},pic=#{pic},createtime=#{createtime}
where id=#{id}
</update>
4、窄化请求映射
在class上添加@RequestMapping(url)指定通用请求前缀, 限制此类下的所有方法请求url必须以请求前缀开头,通过此方法对url进行分类管理。
这种情况就会一个路径可以找到两个方法,产生错误
如下:
@RequestMapping放在类名上边,设置请求前缀
@Controller
@RequestMapping("/item")
方法名上边设置请求映射url:
@RequestMapping放在方法名上边,如下:
@RequestMapping("/queryItem ")
访问地址为:/item/queryItem
5、重定向和转发
①、重定向:
return "redirect:/itemsList.do" /在下面这种情况不能省略
@RequestMapping("/item/updateSubmit")
public String updateSubmit(Item item){
itemService.updateItemByID(item);
return "redirect:itemsList.do";
}
这种方式重定向的路径为 /item/itemList.do
如果两个方法的路径在同一级的话,那么 / 可以去掉(这是下面说的本类重定向)-----不是在同一个类里面也可以,同一级就行
* 需求:重定向
* 本类重定向:
* 1,return "redirect:list.html"
* 2,return "redirect:/red/list.html"
* 跨类重定向:
* 1,return "redirect:/itemsList.html" 必须要有 / 或者根路径
②、转发:
@Controller
@RequestMapping("for")
public class ForwardController {
@RequestMapping("list")
public String list(){
System.out.println("hhhhhh");
return null;
}
/**
* 需求:转发
* 本类转发:
* 语法:
* 1,return "forward:list.html"
* 2,return "forward:/red/list.html"
* 跨类转发:
* 1,return "forward:/itemsList.html"
*/
public String forward(){
//return "forward:/red/list.html";
//本类转发:
//子路径
//return "forward:list.html";
//return "forward:/for/list.html";
//跨类转发:
return "forward:/itemsList.do";
}
}
6、json转换注解:
@RequestBody: 请求 把json格式请求参数转换为javabean
@ResponseBody: 响应 把javabean对象自动转换json对象,返回页面
注解支持:1、mvc注解驱动 2、Jackson包支持 3、请求json,返回json都是js操作
需要配置 <mvc:annotation-driven />
①、在springmvc中,json数据里面的data参数里面必须用双引号,并且要在外面用单引号括起来(传json整个数据的时候)--在springmvc里面用的多------
contentType:‘application/json;charset=utf-8‘,
data:‘{"name":"黑妹牙膏","price":"999"}‘,
②、传参数的时候,data参数是一个对象,{},外面如果加双引号或者单引号,会得不到数据(struts2)
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<script type="text/javascript" src="${pageContext.request.contextPath}/js/jquery.js" ></script>
<script type="text/javascript">
function reqJson (){
$.ajax({
type:"post",
url:‘${pageContext.request.contextPath}/reqJson.do‘,
contentType:‘application/json;charset=utf-8‘,
data:‘{"name":"黑妹牙膏","price":"999"}‘,
success:function(data){
//返回json对象
alert(data.name);
}
})
}
</script>
<title>Insert title here</title>
</head>
<body>
<button onclick="reqJson();" >请求json,返回json格式的数据</button>
</body>
</html>
@Controller
public class JsonController {
/**
* 需求:跳转传递参数页面
*/
@RequestMapping("json")
public String json(){
return "reqJson";
}
/**
* 需求:接受json格式参数,返回json对象
* @requestBody:接受json格式参数,自动把json格式参数自动转换对象
* @responseBody:自动把返回对象转换成json格式返回
*/
@RequestMapping("reqJson")
@ResponseBody
public Item reqJson(@RequestBody Item item){
System.out.println(item);
return item;
}
}
7、springmvc的异常处理:
①、定义一个可预期的异常类
public class CustomException extends Exception {
//定义一个字符串变量,封装自定义异常信息
private String message;
public void setMessage(String message) {
this.message = message;
}
public String getMessage() {
return message;
}
//构造函数,封装异常信息
public CustomException(String message) {
super(message);
this.message=message;
}
}
②、创建异常处理器:
public class ExceptionResolve implements HandlerExceptionResolver {
@Override
public ModelAndView resolveException(HttpServletRequest req, HttpServletResponse res,
Object obj, Exception ex) {
CustomException ce=null;
//判断异常信息是否是自定义异常
if (ex instanceof CustomException) {
ce=(CustomException) ex;
}else{
//运行时异常信息
ce = new CustomException("运行时异常,请联系管理员!");
}
ModelAndView mv = new ModelAndView();
//设置异常数据
mv.addObject("ex", ce.getMessage());
mv.setViewName("error/error");
return mv;
}
}
③、在springmvc.xml里面配置异常处理器
<!-- 配置全局异常处理器 -->
<bean class="com.itcast.utils.ExceptionResolve" ></bean>
8、文件上传
①、方案:创建一个单独的服务器,单纯存储图片,两台服务器的交互,异步上传
②、需求:上传图片,页面不刷新,图片立马回显,存在另一台服务器,跨服务器
③、技术:ajax jersy-io(跨服务器) commons-io、commons-fileupload(上传)
④、文件上传的环境
⑤、springmvc.xml中配置上传文件的解析器
注意:必须配置 id ,并且为 multipartResolver
<!-- 上传文件解析器 -->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver" >
<property name="maxUploadSize" value="10240000" ></property><!-- 单位字节 -->
</bean>
⑥、图片服务器搭建
创建新的服务器:
修改新的服务器的端口号:
修改服务器权限:
⑦、ajax异步上传:
jsp页面:
<form id="itemForm" action="${pageContext.request.contextPath}/item/updateSubmit" method="post" >
<td>
<!-- 图片回显 -->
<img id="imgSize1ImgSrc" src="" height="100" width="100" >
<!-- ajax异步上传函数 -->
<input type="file" id="imgSize1File" name="imgSize1File" class="file" onchange="submitImgSize1Upload" >
<!-- 保存数据库图片地址 -->
<input type="hidden" id="imgSize1" name="pic" value="" reg="^.+$" tip="亲,您忘记上传图片了" >
</td>
- </form>
js代码:
为了使ajax提交的时候,request域中有文件的流对象,所以需要将表单"异步"提交
<script type="text/javascript" src="${pageContext.request.contextPath}/js/jquery.js" ></script>
<script type="text/javascript" src="${pageContext.request.contextPath}/js/jquery.form.js" ></script>
<script type="text/javascript">
function submitImgSize1Upload(){
var option={
type:‘post‘,
url:‘${pageContext.request.contextPath}/uploadPic.do‘,
dataType:‘text‘,
data:{
fileName:‘imgSize1File‘
},
success:function(data){
//把返回json格式字符串转换json对象
var obj = $.parseJSON(data);
//图片立马回显
$("#imgSize1ImgSrc").attr("src",obj.fullPath);
//图片保存数据地址
$("#imgSize1").val(obj.fullPath);
}
};
//使用ajax异步提交表单
$("#itemForm").ajaxSubmit(option);
}
</script>
也可以直接把dataType改成"json",在success函数中就不用转换了(原本是字符串转换为json对象)
⑧、后台代码:
新建一个UpLoadController类
* 需求:上传文件:avi,xls,doc,jpg
* 参数:String fileName,HttpServletRequest,PrintWriter
* 返回值:void
public class UploadController {
/**
* 需求:上传文件:avi,xls,doc,jpg
* 参数:String fileName,HttpServletRequest,PrintWriter
* 返回值:void
*/
@RequestMapping("/uploadPic")
public void uploadPic(String fileName,HttpServletRequest request,PrintWriter out){
//把request转换多部件对象
MultipartHttpServletRequest mh = (MultipartHttpServletRequest) request;
//获取文件对象
CommonsMultipartFile cm = (CommonsMultipartFile) mh.getFile(fileName);
//获取文件扩展名
//a、获取文件名称
String originalFilename = cm.getOriginalFilename();
//b、截取文件扩展名
String extName = originalFilename.substring(originalFilename.lastIndexOf("."));
//使用uuid生成文件名称
String fName = UUID.randomUUID().toString();
//上传文件 jersey工具
Client create = Client.create();
//制定上传的服务器路径
WebResource resource = create.resource(Constants.IMAGE_ADDR+"upload/"+fName+extName);
//上传
resource.put(String.class, cm.getBytes());
//图片回显,需要图片地址返回给ajax的回调函数
//返回json格式数据
String fullPath = Constants.IMAGE_ADDR+"upload/"+fName+extName;
//构造一个json格式数据
String result="{\"fullPath\":\""+fullPath+"\"}";
//返回
out.print(result);
}
}
⑨、修改保存图片
直接提交就可以了
三、restfull软件设计
restfull是一种软件架构设计风格模式
特点:请求没有参数,没有扩展名
案例:http://geek.csdn.net/news/detail/200288 (restfull风格请求)
优点:简洁,容易被搜索引擎系统收录
springmvc实现restfull风格软件架构
1、 springmvc URI模板映射
@RequestMapping("list/{ids}/{name}")
public String findAllItems(@Pathvariable("ids") int id,@Pathvariable String name ,Model model){
url中的{id}会自动映射到参数id上,{name}和参数中的name匹配,可以取别名
2、servlet拦截目录
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/</url-pattern><!-- 拦截所有,包括css,js,images -->
</servlet-mapping>
3、配置springmvc不拦截静态资源
<!-- 放行资源文件 -->
<!--
<mvc:resources location="/css/" mapping="/css/**"></mvc:resources>
<mvc:resources location="/js/" mapping="/js/**"></mvc:resources>
<mvc:resources location="/images/" mapping="/images/**"></mvc:resources>
-->
<!-- 简单写法 -->
<mvc:default-servlet-handler/>
如果不加这个注释(静态资源放行),那么可以直接用url在浏览器的地址栏访问jsp页面,但是不能访问html和image或者css、js文件
/ 不拦截jsp可以在url中直接访问jsp
/* 拦截jsp不能在url中直接访问jsp,return的结果视图也不行,所以不用
四、拦截器:
1、简单测试:
public class Interceptor1 implements HandlerInterceptor{
@Override
public boolean preHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2) throws Exception {
System.out.println("这是第一个拦截器的preHandle");
return true;
}
@Override
public void postHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, ModelAndView arg3)
throws Exception {
System.out.println("这是第一个拦截器的postHandle");
}
@Override
public void afterCompletion(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, Exception arg3)
throws Exception {
System.out.println("这是第一个拦截器的afterCompletion");
}
}
第二个拦截器一样,return false
preHandle:处理器映射器执行之前进行执行,拦截:return false;放行:return true;
postHandle:返回model和view之前执行
afterCompletion:返回model和view之后执行
在springmvc中配置拦截器:
<!-- 配置拦截器 -->
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<bean class="com.itcast.interceptor.Interceptor1" ></bean>
</mvc:interceptor>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<bean class="com.itcast.interceptor.Interceptor2" ></bean>
</mvc:interceptor>
</mvc:interceptors>
按照上面的配置,先运行拦截器1,再运行2
①、如果第一个拦截器return false;第二个是false或者true,那么都返回:
这是第一个拦截器的preHandle
②、如果第一个拦截器return true ;第二个拦截器return false,那么返回:
这是第一个拦截器的preHandle这是第二个拦截器的preHandle
这是第一个拦截器的afterCompletion
③、如果第一个和第二个拦截器都return true ,那么返回:
这是第一个拦截器的preHandle这是第二个拦截器的preHandle
这是第二个拦截器的postHandle
这是第一个拦截器的postHandle
这是第二个拦截器的afterCompletion
这是第一个拦截器的afterCompletion
注意:如果preHandle拦截器返回true,那么afterCompletion必须执行
五、拦截器登录案例
public class LoginInterceptor implements HandlerInterceptor{
//判断用户是否登录
@Override
public boolean preHandle(HttpServletRequest req, HttpServletResponse res, Object obj) throws Exception {
//登录页面,登录请求放行
if (req.getRequestURI().contains("login")) {
//放行
return true;
}
Object user = req.getSession().getAttribute("user");
if (user!=null) {
return true;
}
//如果未登录,跳转登录页面
req.getRequestDispatcher("WEB-INF/jsp/login.jsp").forward(req, res);
return false;
}
<mvc:interceptor>
<mvc:mapping path="/**"/>
<bean class="com.itcast.interceptor.LoginInterceptor" ></bean>
</mvc:interceptor>
@Controller
public class LoginController {
@RequestMapping("login")
public String login(String username,String password,HttpSession session){
session.setAttribute("user", username);
return "redirect:/itemsList";
}
}
p.MsoNormal { margin: 0pt; margin-bottom: .0001pt; text-align: justify; font-family: "Times New Roman"; font-size: 10.5000pt }
span.10 { font-family: "Times New Roman" }
span.15 { font-family: "Times New Roman" }
p.MsoFooter { margin: 0pt; margin-bottom: .0001pt; text-align: left; font-family: "Times New Roman"; font-size: 9.0000pt }
p.MsoHeader { margin: 0pt; margin-bottom: .0001pt; border-bottom: 1.0000pt solid windowtext; padding: 0pt 0pt 1pt 0pt; text-align: center; font-family: "Times New Roman"; font-size: 9.0000pt }
span.msoIns { text-decoration: underline; color: blue }
span.msoDel { text-decoration: line-through; color: red }
div.Section0 { }